unit Main;

interface
uses
  DBClient,
  Windows, Classes, Graphics, Controls, Forms, Dialogs, Generics.collections,
  ExtCtrls, StdCtrls, Mask, Grids, DB, DBTables, Menus, Gauges, Buttons,
  ComCtrls, MUDAnsi, MPlayer, Messages, MMSystem, WSocket, HttpProt,
  Timing,
  OverbyteIcsHttpProt, OverbyteIcsWndControl, OverbyteIcsTnCnx;

type
  TFormMain = class(TForm)
    MainMenu: TMainMenu;
    MenuShowTell: TMenuItem;
    MenuEvents: TMenuItem;
    MenuMacros: TMenuItem;
    MenuProgramOptions: TMenuItem;
    MenuQuickchars: TMenuItem;
    PanelBaseBar: TPanel;
    EditHistory: TEdit;
    MenuRecord: TMenuItem;
    TimerRecordPulse: TTimer;
    MenuHelp: TMenuItem;
    MenuFile: TMenuItem;
    MenuExit: TMenuItem;
    MenuAliases: TMenuItem;
    MenuActions: TMenuItem;
    MenuOpenAutotyper: TMenuItem;
    MenuLock: TMenuItem;
    TimerLED: TTimer;
    TimerRecord: TTimer;
    MenuAutotype: TMenuItem;
    MenuMapper: TMenuItem;
    PanelMain: TPanel;
    PanelScroll: TPanel;
    MUDAnsi: TMUDAnsi;
    PanelSeparator: TPanel;
    MenuPanic: TMenuItem;
    MenuAutotyper: TMenuItem;
    MenuShowToolbar: TMenuItem;
    MenuOptions: TMenuItem;
    IconClock: TImage;
    IconMain: TImage;
    Telnet: TTnCnx;
    MenuEdit: TMenuItem;
    MenuCopy: TMenuItem;
    MenuCopyToAutotyper: TMenuItem;
    MenuIncreaseFont: TMenuItem;
    MenuDecreaseFont: TMenuItem;
    MenuReconnect: TMenuItem;
    MenuShowStatusbar: TMenuItem;
    PanelLeftBar: TPanel;
    LEDScrollback: TShape;
    MenuFont: TMenuItem;
    DialogFont: TFontDialog;
    IconLock: TImage;
    MenuPaste: TMenuItem;
    MenuClearScrollback: TMenuItem;
    MenuScrollback: TMenuItem;
    MenuShowImagery: TMenuItem;
    MemoCopy: TMemo;
    MenuShowFiltered: TMenuItem;
    MenuNicknames: TMenuItem;
    PanelStatusbar: TPanel;
    LabelTime: TLabel;
    LEDFilter: TShape;
    PanelCloseHelpBar: TPanel;
    BtnCloseHelpBar: TSpeedButton;
    TimerSend: TTimer;
    Scrollback: TMUDAnsiSB;
    ImageClock4: TImage;
    PanelScrollTop: TPanel;
    LabelTop: TLabel;
    BevelTotal: TBevel;
    LabelTotal: TLabel;
    PanelStatus: TPanel;
    LabelStatus: TLabel;
    MenuCustomizeToolbar: TMenuItem;
    PopupToolbar: TPopupMenu;
    LEDImageFilter: TImage;
    TimerBanner: TTimer;
    CheckDebug: TCheckBox;
    PanelBars: TPanel;
    PanelToolbar: TPanel;
    BtnExit: TSpeedButton;
    BtnReconnect: TSpeedButton;
    BtnLock: TSpeedButton;
    BtnAliases: TSpeedButton;
    BtnMacros: TSpeedButton;
    BtnQuickchars: TSpeedButton;
    BtnEvents: TSpeedButton;
    BtnNicknames: TSpeedButton;
    BtnViewFiltered: TSpeedButton;
    BtnAutotyper: TSpeedButton;
    BtnAutotype: TSpeedButton;
    BtnCopy: TSpeedButton;
    BtnCopyToAutotyper: TSpeedButton;
    BtnPaste: TSpeedButton;
    BtnReduceFont: TSpeedButton;
    BtnIncreaseFont: TSpeedButton;
    BtnFont: TSpeedButton;
    BtnOptions: TSpeedButton;
    BtnTell: TSpeedButton;
    BtnImagery: TSpeedButton;
    BtnHelp: TSpeedButton;
    BtnPanic: TSpeedButton;
    BtnClearScrollback: TSpeedButton;
    BtnToolbar: TSpeedButton;
    BtnEscape: TSpeedButton;
    BtnScrollback: TSpeedButton;
    PanelRecordBase: TPanel;
    BtnCloseToolbar: TSpeedButton;
    PanelRecord: TPanel;
    MacroPulse2: TImage;
    MacroStop: TImage;
    MacroPulse1: TImage;
    MacroRecord: TImage;
    BtnRecord: TSpeedButton;
    BtnMac: TSpeedButton;
    BtnAli: TSpeedButton;
    m1: TSpeedButton;
    m2: TSpeedButton;
    m4: TSpeedButton;
    m3: TSpeedButton;
    m6: TSpeedButton;
    m5: TSpeedButton;
    m7: TSpeedButton;
    m8: TSpeedButton;
    m10: TSpeedButton;
    m9: TSpeedButton;
    m12: TSpeedButton;
    m11: TSpeedButton;
    MemoPaste: TMemo;
    MenuClearFilteredText: TMenuItem;
    LabelDelay: TLabel;
    TimerDelay: TTimer;
    ImageClock3: TImage;
    ImageClock2: TImage;
    ImageClock1: TImage;
    ImageClock5: TImage;
    ImageClock6: TImage;
    ImageClock7: TImage;
    ImageClock8: TImage;
    LabelBuffered: TLabel;
    BtnDisconnect: TSpeedButton;
    MenuDisconnect: TMenuItem;
    PanelHP2Bar: TPanel;
    ImageHP2: TImage;
    ImageSP2: TImage;
    ImageGP12: TImage;
    ImageGP22: TImage;
    GaugeHP: TGauge;
    GaugeGP1: TGauge;
    GaugeGP2: TGauge;
    GaugeEnemy: TGauge;
    ImageEnemy2: TImage;
    MenuShowHPBar: TMenuItem;
    ihp1: TImage;
    isp1: TImage;
    igp11: TImage;
    igp21: TImage;
    ImageEnemyName: TImage;
    ihp3: TImage;
    isp3: TImage;
    igp13: TImage;
    igp23: TImage;
    LEDConnected: TImage;
    LEDDisconnected: TImage;
    MenuClearKeyhistory: TMenuItem;
    BtnClearKeyhistory: TSpeedButton;
    igp12: TImage;
    ihp2: TImage;
    isp2: TImage;
    igp22: TImage;
    MenuWindow: TMenuItem;
    MenuCaptureScrollback: TMenuItem;
    DialogSave: TSaveDialog;
    BtnCapture: TSpeedButton;
    PanelHP1Bar: TPanel;
    MenuShowHP2Bar: TMenuItem;
    LabelHPMax: TLabel;
    LabelHP: TLabel;
    LabelSlash1: TLabel;
    LabelSP: TLabel;
    LabelSlash2: TLabel;
    LabelSPMax: TLabel;
    LabelGP1: TLabel;
    LabelSlash3: TLabel;
    LabelGP1Max: TLabel;
    LabelGP2: TLabel;
    LabelSlash4: TLabel;
    LabelGP2Max: TLabel;
    ImageHP: TImage;
    ImageSP: TImage;
    ImageGP1: TImage;
    ImageGP2: TImage;
    LEDLogOff: TImage;
    LEDLogOn: TImage;
    MenuSetupGroups: TMenuItem;
    BtnGroups: TSpeedButton;
    EditTab: TEdit;
    MenuShowChat: TMenuItem;
    MenuPasteCommandLine: TMenuItem;
    MenuCopyCommandLine: TMenuItem;
    MenuCutCommandLine: TMenuItem;
    MenuSetupDisplayColors: TMenuItem;
    MenuLogToFile: TMenuItem;
    BtnDisplay: TSpeedButton;
    BtnChat: TSpeedButton;
    PanelScrollBottom: TPanel;
    LabelBottom: TLabel;
    LabelSTotal: TLabel;
    MenuAnchor: TMenuItem;
    MenuAnchorTell: TMenuItem;
    MenuAnchorImagery: TMenuItem;
    BtnLog: TSpeedButton;
    BtnClearFiltered: TSpeedButton;
    MenuActivateBASE: TMenuItem;
    BtnBASE: TSpeedButton;
    EditEsc: TEdit;
    MenuInsertEscChar: TMenuItem;
    MenuGroups: TMenuItem;
    ListHistory: TListBox;
    ListHistoryIndex: TListBox;
    EditSearch: TEdit;
    BtnCloseScrollback: TSpeedButton;
    MenuTicker: TMenuItem;
    BtnTicker: TSpeedButton;
    BevelTicker: TBevel;
    PanelHP3Bar: TPanel;
    MenuShowHP3Bar: TMenuItem;
    GLine2: TRichEdit;
    PanelHP4Bar: TPanel;
    PanelSpecial: TPanel;
    PanelSpecial2: TPanel;
    MenuShowHP4Bar: TMenuItem;
    LabelSpecial: TLabel;
    LabelSpecial2: TLabel;
    BtnFind: TSpeedButton;
    BtnNext: TSpeedButton;
    MenuFind: TMenuItem;
    MenuFindNext: TMenuItem;
    BtnPrior: TSpeedButton;
    MenuSendPassword: TMenuItem;
    BtnJumpstart: TSpeedButton;
    MenuJumpstart: TMenuItem;
    PopupCopyA: TMenuItem;
    PopupCut: TMenuItem;
    PopupCopy: TMenuItem;
    MenuInsertBeep: TMenuItem;
    EditBeep: TEdit;
    MenuCopyDownloadA: TMenuItem;
    MenuCopyDownload: TMenuItem;
    LEDDownloadT: TImage;
    LEDDownloadF: TImage;
    PanelDownload: TPanel;
    GaugeDownload: TGauge;
    ImageDownload: TImage;
    MenuClearDownload: TMenuItem;
    BtnDownloadA: TSpeedButton;
    BtnDownloadF: TSpeedButton;
    BtnClearDownload: TSpeedButton;
    LabelDownload: TLabel;
    BtnCancelDownload: TSpeedButton;
    PopupCopyDownloadA: TMenuItem;
    PopupCaptureDownload: TMenuItem;
    PopupClearDownload: TMenuItem;
    PopupDisconnect: TMenuItem;
    PopupLogIncoming: TMenuItem;
    MenuSendDelimited: TMenuItem;
    MenuPasteCursor: TMenuItem;
    BtnPasteCursor: TSpeedButton;
    PopupPasteCursor: TMenuItem;
    MenuUpload: TMenuItem;
    DialogOpen: TOpenDialog;
    TimerUpload: TTimer;
    BtnUpload: TSpeedButton;
    BtnMapper: TSpeedButton;
    MenuNext: TMenuItem;
    MenuClearBuffer: TMenuItem;
    MenuVars: TMenuItem;
    BtnVars: TSpeedButton;
    DialogOpenPlaylist: TOpenDialog;
    MenuIO: TMenuItem;
    MenuSecondary: TMenuItem;
    Tool3: TMenuItem;
    Tool4: TMenuItem;
    Tool5: TMenuItem;
    Tool6: TMenuItem;
    Tool7: TMenuItem;
    Tool8: TMenuItem;
    Tool9: TMenuItem;
    Tool0: TMenuItem;
    Tool1: TMenuItem;
    Tool2: TMenuItem;
    NoTools: TMenuItem;
    MenuPasteDelimited: TMenuItem;
    MenuShowCartographer: TMenuItem;
    MenuAnchorMap: TMenuItem;
    BtnMap: TSpeedButton;
    HTTP: THttpCli;
    TimerGrabData: TTimer;
    ImageGA: TImage;
    PanelSends: TPanel;
    MemoSends: TMemo;
    LabelSends: TLabel;
    BtnShowSends: TSpeedButton;
    MenuShowRecordTool: TMenuItem;
    MenuAnchorFiltered: TMenuItem;
    MenuQuickEvent: TMenuItem;
    BtnQuickEvent: TSpeedButton;
    Telnet2: TTnCnx;
    PanelSecondary: TPanel;
    BtnMUD1: TSpeedButton;
    BtnMUD2: TSpeedButton;
    TimerHistory: TTimer;
    TimerHistory2: TTimer;
    MenuInsertLineBreak: TMenuItem;
    PanelMessageBase: TPanel;
    PanelAnnounce: TPanel;
    LabelMessage: TLabel;
    PanelMessageRight: TPanel;
    ImageRegister: TImage;
    BtnCloseMessage: TSpeedButton;
    PanelMessageLeft: TPanel;
    MenuHPBar: TMenuItem;
    MenuShowCanvas: TMenuItem;
    MenuAnchorCanvas: TMenuItem;
    MP: TMediaPlayer;
    MenuMusic: TMenuItem;
    MenuMusicPlay: TMenuItem;
    MenuMusicPause: TMenuItem;
    MenuMusicRewind: TMenuItem;
    MenuMusicOpen: TMenuItem;
    MenuMusicRepeat: TMenuItem;
    BtnMusicPlay: TSpeedButton;
    BtnMusicLast: TSpeedButton;
    BtnMusicRewind: TSpeedButton;
    BtnCanvas: TSpeedButton;
    BtnMusicOpen: TSpeedButton;
    TimerSpecial: TTimer;
    TimerSpecial2: TTimer;
    TimerHP: TTimer;
    TimerSP: TTimer;
    TimerGP1: TTimer;
    TimerGP2: TTimer;
    PanelLeftMUDAnsi: TPanel;
    PanelLeftScrollback: TPanel;
    TimerAutoDownload: TTimer;
    MenuCloseAllScreens: TMenuItem;
    TimerChart: TTimer;
    ImageEnemyLow: TImage;
    ImageEnemyMedian: TImage;
    ImageEnemyHigh: TImage;
    ImageEnemyLow2: TImage;
    ImageEnemyMedian2: TImage;
    ImageEnemyHigh2: TImage;
    ImageEnemyBetter2: TImage;
    ImageDisableEvent: TImage;
    ImageEnableEvent: TImage;
    ImageEnemyBetter: TImage;
    ImageEnemy: TImage;
    GaugeEnemy2: TGauge;
    ImageEnemyName2: TImage;
    ImageHP1Bar: TImage;
    BtnCloseHP1: TSpeedButton;
    ImageHP2Bar: TImage;
    BtnCloseHP2: TSpeedButton;
    BtnCloseHP3: TSpeedButton;
    BtnCloseHP4: TSpeedButton;
    GaugeSP: TGauge;
    ShapeHP: TShape;
    ShapeSP: TShape;
    ShapeGP1: TShape;
    ShapeGP2: TShape;
    ShapeEnemy: TShape;
    ShapeEnemy2: TShape;
    PanelSend: TPanel;
    EditSend: TMemo;
    PanelLED: TPanel;
    ImageLeftBarBottom: TImage;
    DialogOpen3: TOpenDialog;
    MenuSecondaryDisconnect: TMenuItem;
    MenuSecondaryReverse: TMenuItem;
    LEDSecondaryDisconnected: TImage;
    LEDSecondaryConnected: TImage;
    PopupSecondaryDisconnect: TMenuItem;
    PopupSecondaryConnect: TMenuItem;
    BtnSecondary: TSpeedButton;
    MenuHotkeys: TMenuItem;
    BtnSecondaryDisconnect: TSpeedButton;
    BtnSecondaryReverse: TSpeedButton;
    BtnHotkeys: TSpeedButton;
    LEDBob: TImage;
    PopupBobMe: TMenuItem;
    BtnIO: TSpeedButton;
    DialogOpen4: TOpenDialog;
    MenuSendTextFile: TMenuItem;
    BtnSendTextFile: TSpeedButton;
    LedMidBob: TImage;
    MenuShowRoom: TMenuItem;
    MenuAnchorRoom: TMenuItem;
    MenuMusicNext: TMenuItem;
    MenuMusicPrevious: TMenuItem;
    BtnMusicPrevious: TSpeedButton;
    BtnMusicNext: TSpeedButton;
    BtnMusicLoad: TSpeedButton;
    MenuMusicLoad: TMenuItem;
    MenuMusicFirst: TMenuItem;
    MenuMusicLast: TMenuItem;
    BtnMusicPause: TSpeedButton;
    BtnMusicFirst: TSpeedButton;
    MenuMusicRandomize: TMenuItem;
    TimerMusic: TTimer;
    MenuAutoscribble: TMenuItem;
    BtnAutoscribble: TSpeedButton;
    LabelEName: TLabel;
    LabelEName2: TLabel;
    MP2: TMediaPlayer;
    TimerRepeat: TTimer;
    EditAlias: TComboBox;
    EditMacro: TComboBox;
    GLine1: TRichEdit;
    PanelHP3Split: TSplitter;
    PanelHP4Split: TSplitter;
    CommonScripts: TMenuItem;
    procedure EditSendKeyPress(Sender: TObject; var Key: Char);
    procedure FormCreate(Sender: TObject);
    procedure MacroMasterClick(Sender: TObject);
    procedure MenuShowTellClick(Sender: TObject);
    procedure MenuEventsClick(Sender: TObject);
    procedure MenuMacrosClick(Sender: TObject);
    procedure MenuProgramOptionsClick(Sender: TObject);
    procedure MenuQuickcharsClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormResize(Sender: TObject);
    procedure BtnRecordClick(Sender: TObject);
    procedure TimerRecordPulseTimer(Sender: TObject);
    procedure MenuAboutClick(Sender: TObject);
    procedure MenuExitClick(Sender: TObject);
    procedure MenuAliasesClick(Sender: TObject);
    procedure MenuOpenAutotyperClick(Sender: TObject);
    procedure MenuLockClick(Sender: TObject);
    procedure TimerLEDTimer(Sender: TObject);
    procedure TimerRecordTimer(Sender: TObject);
    procedure BtnMacClick(Sender: TObject);
    procedure MenuAutotypeClick(Sender: TObject);
    procedure MenuMapperClick(Sender: TObject);
    procedure MenuHelpTopicsClick(Sender: TObject);
    procedure TelnetDataAvailable(Sender: TTnCnx; Buffer: Pointer;
      Len: Integer);
    procedure MenuPanicClick(Sender: TObject);
    procedure PanelSeparatorMouseMove(Sender: TObject; Shift: TShiftState;
      X, Y: Integer);
    procedure PanelSeparatorMouseDown(Sender: TObject;
      Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    procedure PanelSeparatorMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure MenuEscapeClick(Sender: TObject);
    procedure MUDAnsiCodeReceived(DATA: string);
    procedure MenuDoScrollbackClick(Sender: TObject);
    procedure TimerTimeTimer(Sender: TObject);
    procedure MenuScrollforwardClick(Sender: TObject);
    procedure TelnetSessionConnected(Sender: TTnCnx; Error: Word);
    procedure TelnetSessionClosed(Sender: TTnCnx; Error: Word);
    procedure MenuScrollWAYBackClick(Sender: TObject);
    procedure MenuScrollWAYDownClick(Sender: TObject);
    procedure MenuCopyClick(Sender: TObject);
    procedure MenuCopyToAutotyperClick(Sender: TObject);
    procedure MenuDecreaseFontClick(Sender: TObject);
    procedure MenuBarWAYUpClick(Sender: TObject);
    procedure MenuReconnectClick(Sender: TObject);
    procedure MenuHomeAllClick(Sender: TObject);
    procedure BtnExitMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure MenuFontClick(Sender: TObject);
    procedure MenuPasteClick(Sender: TObject);
    procedure MenuClearScrollbackClick(Sender: TObject);
    procedure EditSendChange(Sender: TObject);
    procedure MUDAnsiCopyToAutotyper(DATA: string);
    procedure MenuNicknamesClick(Sender: TObject);
    procedure MUDAnsiFilter(DATA: string);
    procedure BtnTellClick(Sender: TObject);
    procedure BtnCloseToolbarClick(Sender: TObject);
    procedure TimerSendTimer(Sender: TObject);
    procedure FormKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure MenuCustomizeToolbarClick(Sender: TObject);
    procedure TimerBannerTimer(Sender: TObject);
    procedure EditAliasClick(Sender: TObject);
    procedure m1Click(Sender: TObject);
    procedure MenuShowToolbarClick(Sender: TObject);
    procedure MenuClearFilteredTextClick(Sender: TObject);
    procedure TimerDelayTimer(Sender: TObject);
    procedure MenuDisconnectClick(Sender: TObject);
    procedure MenuClearKeyhistoryClick(Sender: TObject);
    procedure MUDAnsiClick(Sender: TObject);
    procedure MUDAnsiBeep(Sender: TObject);
    procedure MenuCaptureScrollbackClick(Sender: TObject);
    procedure MenuSetupGroupsClick(Sender: TObject);
    procedure MUDAnsiLineCompleted(str: string; ob: TObject);
    procedure MenuTabClick(Sender: TObject);
    procedure MenuPasteCommandLineClick(Sender: TObject);
    procedure MenuCutCommandLineClick(Sender: TObject);
    procedure MenuSetupDisplayColorsClick(Sender: TObject);
    procedure MenuLogToFileClick(Sender: TObject);
    procedure MenuAnchorClick(Sender: TObject);
    procedure LEDLogOnClick(Sender: TObject);
    procedure MenuAnchorAllClick(Sender: TObject);
    procedure MenuActivateBASEClick(Sender: TObject);
    procedure MenuInsertEscCharClick(Sender: TObject);
    procedure ListHistoryIndexClick(Sender: TObject);
    procedure BtnCloseScrollbackClick(Sender: TObject);
    procedure MenuTickerClick(Sender: TObject);
    procedure LabelTickerDblClick(Sender: TObject);
    procedure PopupResetTickerClick(Sender: TObject);
    procedure MenuCtrlTabClick(Sender: TObject);
    procedure MenuCtrlTab2Click(Sender: TObject);
    procedure PanelHP3SplitMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure PanelHP3SplitMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure PanelHP3SplitMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure PanelHP4SplitMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure PanelHP4SplitMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure PanelHP4SplitMouseMove(Sender: TObject; Shift: TShiftState;
      X, Y: Integer);
    procedure MenuFindClick(Sender: TObject);
    procedure MenuFindNextClick(Sender: TObject);
    procedure MenuSendPasswordClick(Sender: TObject);
    procedure PopupHP3Click(Sender: TObject);
    procedure PopupHP4Click(Sender: TObject);
    procedure MenuJumpstartClick(Sender: TObject);
    procedure ListHistoryDrawItem(Control: TWinControl; Index: Integer;
      Rect: TRect; State: TOwnerDrawState);
    procedure ListHistoryMeasureItem(Control: TWinControl; Index: Integer;
      var Height: Integer);
    procedure MenuInsertBeepClick(Sender: TObject);
    procedure PopupUndoClick(Sender: TObject);
    procedure PopupCommandLinePopup(Sender: TObject);
    procedure MenuCopyDownloadAClick(Sender: TObject);
    procedure MenuCopyDownloadClick(Sender: TObject);
    procedure MenuClearDownloadClick(Sender: TObject);
    procedure LEDImageFilterClick(Sender: TObject);
    procedure MenuSendDelimitedClick(Sender: TObject);
    procedure MenuPasteCursorClick(Sender: TObject);
    procedure MenuUploadClick(Sender: TObject);
    procedure TimerUploadTimer(Sender: TObject);
    procedure BtnViewFilteredClick(Sender: TObject);
    procedure MenuNextClick(Sender: TObject);
    procedure MenuClearBufferClick(Sender: TObject);
    procedure MUDAnsiTrigger(index: Integer; variables: strarray);
    procedure MenuVarsClick(Sender: TObject);
    procedure MUDAnsiLinkClick(target: string);
    procedure MenuSetupToolsClick(Sender: TObject);
    procedure Tool1Click(Sender: TObject);
    procedure MenuLiteralClick(Sender: TObject);
    procedure CtrlA1Click(Sender: TObject);
    procedure BtnUpOneClick(Sender: TObject);
    procedure TimerGrabDataTimer(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure BtnCloseSendsClick(Sender: TObject);
    procedure BtnShowSendsClick(Sender: TObject);
    procedure MenuShowRecordToolClick(Sender: TObject);
    procedure FormKeyUp(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure MenuQuickEventClick(Sender: TObject);
    procedure TimerHistoryTimer(Sender: TObject);
    procedure TimerHistory2Timer(Sender: TObject);
    procedure MenuInsertLineBreakClick(Sender: TObject);
    procedure PanelAnnounceClick(Sender: TObject);
    procedure FormMouseWheelUp(Sender: TObject; Shift: TShiftState;
      MousePos: TPoint; var Handled: Boolean);
    procedure FormMouseWheelDown(Sender: TObject; Shift: TShiftState;
      MousePos: TPoint; var Handled: Boolean);
    procedure MenuHPBarClick(Sender: TObject);
    procedure MenuTelnetClick(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure MPNotify(Sender: TObject);
    procedure MenuMusicPlayClick(Sender: TObject);
    procedure MenuMusicOpenClick(Sender: TObject);
    procedure MenuMusicRepeatClick(Sender: TObject);
    procedure TimerSpecialTimer(Sender: TObject);
    procedure TimerHPTimer(Sender: TObject);
    procedure TimerAutoDownloadTimer(Sender: TObject);
    procedure MenuCloseAllScreensClick(Sender: TObject);
    procedure PopupGLine1Click(Sender: TObject);
    procedure TimerChartTimer(Sender: TObject);
    procedure ImageDisableEventClick(Sender: TObject);
    procedure MenuHP1BarSkinClick(Sender: TObject);
    procedure MenuHP1BarSkinClearClick(Sender: TObject);
    procedure MenuHP1FontClick(Sender: TObject);
    procedure MenuHP1BarBackgroundClick(Sender: TObject);
    procedure DefaultHP1BarFont1Click(Sender: TObject);
    procedure Telnet2SessionClosed(Sender: TTnCnx; Error: Word);
    procedure Telnet2SessionConnected(Sender: TTnCnx; Error: Word);
    procedure MenuSecondaryClick(Sender: TObject);
    procedure MenuSecondaryDisconnectClick(Sender: TObject);
    procedure MenuSecondaryReverseClick(Sender: TObject);
    procedure BtnMUD1Click(Sender: TObject);
    procedure MenuHotkeysClick(Sender: TObject);
    procedure MenuIOClick(Sender: TObject);
    procedure MenuSendTextFileClick(Sender: TObject);
    procedure MenuScottClick(Sender: TObject);
    procedure MenuShowRoomClick(Sender: TObject);
    procedure MenuTabShiftClick(Sender: TObject);
    procedure MenuMusicNextClick(Sender: TObject);
    procedure MenuMusicLoadClick(Sender: TObject);
    procedure MenuMusicFirstClick(Sender: TObject);
    procedure MenuMusicRandomizeClick(Sender: TObject);
    procedure TimerMusicTimer(Sender: TObject);
    procedure SuperClick(Sender: TObject);
    procedure MenuAutoscribbleClick(Sender: TObject);
    procedure LabelENameDblClick(Sender: TObject);
    procedure SessionLogs1Click(Sender: TObject);
    procedure TimerRepeatTimer(Sender: TObject);
    procedure EditMacroCloseUp(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure CommonScriptsClick(Sender: TObject);
  private
    { Private declarations }
    AnchorTops: array [0..14] of integer;
    AnchorLefts: array [0..14] of integer;
    procedure WMEnterSizeMove(var MSG: Tmessage);  message WM_ENTERSIZEMOVE;
    procedure WMExitSizeMove(var MSG: Tmessage);  message WM_EXITSIZEMOVE;
    procedure WMSysCommand(var Message: TWMSysCommand); message WM_SYSCOMMAND;
    procedure WMGetMinMaxInfo(var MSG: Tmessage); message WM_GETMINMAXINFO;
    procedure WMMoving(var MSG: Tmessage); message WM_MOVING;
    function FigureTimeString: string;
    procedure SaveOptions(partial: boolean);
    procedure RetrieveHistory;
    procedure DisplayHistory(str: string; col: TColor);
    procedure SearchHistory(dir: string);
    procedure ClearHistoryVars;
    procedure RecordMacro(macro: string);
    function ProcessMulti(const data: string; i: integer; kind: integer): boolean;
    function ProcessAlias(var data: string; kind: integer; over: boolean): boolean;
    procedure ScrollUp(amt: integer);
    procedure ScrollDown(amt: integer);
    function TryAliasMacro(action: string; kind: integer): boolean;
    procedure ShowImage(filename, text: string);
    procedure ShowAVI(filename, text: string; h, w: integer; dorepeat: boolean);
    procedure EnemyImage(data: string);
    function Wildcard(data, wild: string; amt: integer): string;
    procedure DoSend;
    procedure ClearSending;
    procedure UpdateTotalLabel;
    procedure UpdateScrollbackLabels;
    procedure UpdateToolbar;
    procedure UpdateRecordbar;
    procedure HideButtons;
    procedure PositionButton(but, pos: string);
    procedure UpdateBasebar;
    procedure UpdateSendbar;
    procedure ShowMenu(arg: boolean);
    procedure SpecialMessage(data: string);
    procedure HideClocks;
    procedure UpdateLabelBuffered;
    procedure UpdateConnection(conn: integer; status: boolean);
    procedure CheckTicker;
    procedure AddKeyhistory(data: string);
    procedure LogData;
    procedure AddParsing;
    procedure UpdateColors;
    procedure UpdateTools;
    procedure UpdateLogger;
    procedure UpdateMenu;
    procedure CheckRetain;
    procedure ShowDisconnect;
    procedure FigureStatusEvent(which: integer; var action: string; var sound: string);
    procedure DownHistory;
    procedure UpHistory;
    procedure CloseHistory;
    procedure UpdateTickerLabel;
    procedure ToggleTicker;
    procedure UpdateFonts;
    procedure UpdateHyperlinks;
    function ParseParsing(data: string; kind: integer): boolean;
    function ParseGroup(data: string): boolean;
    function ParseSystem(data: string): boolean;
    function ParseTicker(data: string): boolean;
    function ParsePassword(data: string): boolean;
    function ParseLastCommand(data: string; kind: integer): boolean;
    function ParseLogic(data: string; kind: integer): boolean;
    function ParseActions(data: string; kind: integer): boolean;
    function ParseJumpstart(data: string): boolean;
    function ParseFile(data: string): boolean;
    function ParseCanvas(data: string): boolean;
    function ParseEvent(data: string): boolean;
    function ParseAlias(data: string): boolean;
    function ParseMacro(data: string): boolean;
    function ParseQuickchar(data: string): boolean;
    function ParseVariables(data: string): boolean;
    function ParseNickname(data: string): boolean;
    function ParseAutotype(data: string): boolean;
    function ParseCycling(data: string; kind: integer): boolean;
    function ParseProcess(data: string): boolean;
    function ParseCharting(const dir: string; okind: integer): boolean;
    function ParseSprint(data: string): boolean;
    function ParseSecondary(data: string): boolean;
    function ParseRepeat(data: string): boolean;
    procedure UpdateCaption;
    procedure UpdateHP4Bar;
    procedure UpdateMasks;
    procedure StoreAnchors;
    procedure UpdateAnchors;
    procedure ClearStatusFields;
    procedure FinishDownload;
    procedure UpdateDownloadButtons;
    function FigureFColor(kind: integer): integer;
    function FigureBColor(kind: integer): integer;
    function FigureEcho(kind: integer): boolean;
    function CSelect(str: string): string;
    function RSelect(str: string): string;
    function DoSet(str: string): string;
    function DoMath(str: string): string;
    function DoCopy(str: string; kind: integer): string;
    function DoPos(str: string): string;
    function DoSubs(str: string): string;
    function DoSum(str: string; average: boolean): string;
    function DoDateTime(str: string; dat: boolean): string;
    procedure DownloadMedia(filename,URL: string);
    procedure GrabMedia(filename,URL: string);
    function DoDelaying(data: string): boolean;
    procedure UpdateGauge(which: integer; var oldvar: integer; FromOptions: boolean);
    procedure DoAnimation;
    procedure SetGLine(data: string; which: integer);
    procedure ColorGLine(gline: TRichEdit; colorstart, colorlength: integer; col: TColor);
    function FigureGLineColor(str: string): integer;
    procedure FigureEnemyPercent(per: string);
    procedure Special(stag: integer; str: string);
    procedure EnableEvents(b: integer);
    procedure AppendToAutotyper(data: string);
    procedure UpdateHPBars;
    procedure LoadHP(index: integer);
    procedure ChangeControl(index: integer);
    procedure UpdateLED;
    procedure CheckIdlePanic;
    procedure PopulateRecord;
    procedure SendFile(fname: string);
    function NormalizeData(data: string): string;
    procedure LoadEditorOptions;
    procedure ExecuteExternal(data: string);
    procedure LocateParsing(dir: string);
    procedure UpdateMusic;
    procedure LogSession;
    procedure PopulateComboBox(combo: TComboBox; dataset: TCustomClientDataSet;
                               fieldname, textname: string);
  public
    { Public declarations }
    roomshortstring: string;
    panicking, online, loginclose: boolean;
    Download: TStringList;
    procedure Initialize;
    procedure PlaySound(filename: string; now, system, forced: integer; panicforced: boolean);
    procedure LoadOptions;
    procedure SetupEvents;
    procedure PanicClose;
    procedure SendData(str: string; kind: integer);
    procedure NextScreen(from: integer);
    procedure PriorScreen(from: integer);
    procedure OpenFloater(which: integer);
    procedure SystemText(str: string; ul: integer);
    procedure DisableForms;
    procedure EnableForms;
    procedure UpdateFilteredCount;
    function Compile(data: string): string;
    function DoFunction(data: string): string;
    procedure UnloadScreen(which: integer);
    procedure UpdateAutotyperButtons(ena: boolean);
    function GetEName: string;
    procedure ExternalParse(str: string; kind: integer);
    procedure LoadHPImages;
    procedure UpdateCanvasVariable(variable, value: string);
    procedure UpdateWindowCaptions;
    procedure ParseMain(data: string; kind: integer);
    function DoAlias(ali, wild: string; kind: integer; rev, frev, over: boolean): boolean;
    procedure ExecuteAlias(const data, wild: string; kind: integer; rev, frev: boolean);
  private
    tempvar, currentline: string;
    FTickers: TList<TPortalTimestamp>;
    Tags: TStringList;
    screens: array [0..13] of boolean;
    animes: array [0..3] of boolean;
    specials: array [0..2] of integer;
    olds: array [0..3] of integer;
    function PlayMusic(filename: string; dontplay: boolean): integer;
    function DoMacro(mac: string; kind: integer; over: boolean): boolean;
    procedure DoStatusEvent(which: integer);
    procedure LoadScreen(which: integer);
    procedure LoadSkin(index: integer);
    function ParseChartingRoom(work: string): boolean;
    function ParseChartingLabelTag(work, ch: string): boolean;
    function parseChartingStubs(const work: string): boolean;
    function parseChartingChart(work: string; var kind: integer): boolean;
    procedure EditSendEnter(var Key: Char; sels, sell: integer);
    procedure SyncTickers;
    function GetTickerValue(str: string): string;
    procedure ExecuteAliasLine(count: integer; work, wild: string; kind: integer);
    function QuickCharActionRQ(data: string): boolean;
    procedure QuickCharActionQuery;
  end;

var
  FormMain: TFormMain;

implementation

{$R *.DFM}

uses
  SysUtils, StrUtils, ShellAPI, GIFImg, Variants,
  WarnMove, RProperties, EventQ, NewConnection, HP, Session, Canvas, Music, IO,
  Database, ConfirmLink, EnterText, Colors, Ticker, FPassword, Vars, Importing,
  Tools, Map, Note, Toolbar, Disconnect, Groups, Chat, Menu, Room, Tellhist,
  Events, Macros, Options, Actions, Image, Filtered, About, Alias, Editor,
  Secure, Mapper, Clock, Nicknames, ScriptModule, CommonScripts,
  Login;

var
  findtext, passwordbuffer, lastcommand, HistorySearch: string;
  overrideclose, haltsounds, mouseisdown, playing, HisB, recording, bypass: boolean;
  repeatmusic, onlinetime, eventsdone, scrollmin, barbuffer, HistoryI, animate: integer;
  clockphase, delaycounter, maxdelay, commandsdone, CommandsMax, ParsePos, ParsingI: integer;
  EGroups, EEvents, EActions, ESounds, Sounds, History, Parsing: TStringList;
  rebootstring, mudlagstring, editingstring, captionstring: string;
  panicwindows, lastq, uptimestring: string;
  homed, delayeddisconnect, lockshowing, clockshowing, bypassgroup, panicclosing: boolean;
  globaldelay, controlling, hp3mouseisdown, hp4mouseisdown, tabbing, timeflip: boolean;
  DLMedia, Sends, Uploads: TStringList;
  adcycled, adcycledmax, DownloadC, DownloadMax, editsendlines, editsendheight, tickerevents: integer;
  doingctrl, doingsend, shifting, Downloading, showingdisconnect: boolean;
  grabbingmedia, firststatus, scommand, tryingsecond, isnumpad: boolean;
  DownloadString: string;
  enemys: array [0..4] of boolean;
  screenChat: TFormChat;
  screenTell: TFormTellhist;
  screenRoom: TFormRoomMonitor;
  screenImagery: TFormImagery;
  screenFiltered: TFormFiltered;
  screenCanvas: TFormCanvas;
  screenEditor: TFormEditor;

procedure TFormMain.Initialize;
var
  recall: TFontRecall;
begin
  isnumpad:=false;
  homed:=false;
  ImageEnableEvent.hide;
  ImageDisableEvent.show;
  loginclose:=false;
  grabbingmedia:=false;
  ParsePos:=0;
  ParsingI:=0;
  HistoryI:=0;
  animate:=0;
  adcycled:=0;
  adcycledmax:=0;
  LabelMessage.hint:='';
  tickerevents:=0;
  globaldelay:=false;
  controlling:=false;
  doingctrl:=false;
  doingsend:=false;
  tryingsecond:=false;
  tempvar:='';
  findtext:='';
  tabbing:=false;
  panicking:=false;
  panicwindows:='';
  delayeddisconnect:=false;
  Downloading:=false;
  DownloadString:='';
  panicclosing:=false;
  lockshowing:=false;
  clockshowing:=false;
  MenuLogToFile.checked:=false;
  UpdateLogger;
  bypassgroup:=false;
  clockphase:=0;
  delaycounter:=0;
  onlinetime:=0;
  eventsdone:=0;
  commandsdone:=0;
  passwordbuffer:='';
  uptimestring:='';
  rebootstring:='';
  roomshortstring:='';
  mudlagstring:='';
  editingstring:='';
  captionstring:='';
  scommand:=false;
  EditSend.text:='';
  editsendlines:=1;
  overrideclose:=false;
  firststatus:=false;
  haltsounds:=false;
  hp3mouseisdown:=false;
  hp4mouseisdown:=false;
  mouseisdown:=false;
  lastcommand:='';
  currentline:='';
  playing:=false;
  online:=false;
  recording:=false;
  HisB:=false;
  DLMedia.clear;
  Sends.clear;
  Tags.clear;
  Sounds.clear;
  EEvents.clear;
  EGroups.clear;
  EActions.clear;
  ESounds.clear;
  Parsing.clear;
  Datawell.ClearFiltered;
  UpdateFilteredCount;
  bypass:=false;
  PanelScroll.height:=0;
  barbuffer:=1;
  UpdateConnection(1,false);
  TimerTimeTimer(nil);
  shifting:=false;
  screens[0]:=false; //chat
  screens[1]:=false; //tell
  screens[2]:=false; //room
  screens[4]:=false; //imagery
  screens[6]:=false; //filtered
  screens[10]:=false; //canvas
  screens[13]:=false; //game
  animes[0]:=false;
  animes[1]:=false;
  animes[2]:=false;
  animes[3]:=false;
  specials[0]:=0;
  specials[1]:=0;
  specials[2]:=0;
  olds[0]:=0;
  olds[1]:=0;
  olds[2]:=0;
  olds[3]:=0;
  enemys[0]:=true; //enemy
  enemys[1]:=false; //low
  enemys[2]:=false; //median
  enemys[3]:=false; //high
  enemys[4]:=false; //better
  Datawell.lastalias:='';
  Datawell.lastmacro:='';
  Datawell.lastevent:='';
  showingdisconnect:=false;
  recall := TFontRecall.Create(self.Font);
  try
    self.Font := editSend.Font;
    editsendheight := self.canvas.TextHeight('QWERTYUIOPASDFGHjKLMZXCVBNM');
  finally
    recall.Free;
  end;
end;

procedure TFormMain.FormCreate(Sender: TObject);
var
  filename: string;
begin
  FTickers := TObjectList<TPortalTimestamp>.Create(true);
  PanelMessageBase.height:=31;
  PanelToolbar.height:=28;
  PanelStatusbar.height:=17;
  PanelSecondary.width:=0;
  ImageHP1Bar.left:=1;
  ImageHP2Bar.left:=1;
  repeatmusic:=0;
  LabelTime.caption:='';
  LabelDelay.caption:='';
  LabelBuffered.caption:='';
  LabelEName.caption:='';
  LabelEName2.caption:='';
  ListHistory.left:=32;
  ListHistory.height:=116;
  ListHistoryIndex.left:=6;
  ListHistoryIndex.height:=116;
  ListHistoryIndex.width:=53;
  EditHistory.left:=6;
  EditSearch.left:=6;
  EditSend.top:=0;
  EditSend.left:=-1;
  PanelScrollTop.top:=0;
  PanelScrollTop.height:=32;
  PanelScrollTop.width:=32;
  PanelScrollBottom.height:=65;
  PanelScrollBottom.width:=32;
  PanelSends.left:=133;
  PanelSends.width:=321;
  PanelSends.height:=125;
  LabelSends.left:=5;
  MemoSends.left:=2;
  timeflip:=false;
  Datawell.AllCreated:=true;
  lastq:='';
  maxdelay:=99;  // Maximum alias/macro delay (seconds)
  scrollmin:=102;  // Minimum size of the scrollback window
  CommandsMax:=1000;    // Maximum events commands in 5 seconds
  MUDAnsi.scrollback:=Scrollback;
  DLMedia:=TStringList.create;
  Sends:=TStringList.create;
  Tags:=TStringList.create;
  History:=TStringList.create;
  Parsing:=TStringList.create;
  Sounds:=TStringList.create;
  EEvents:=TStringList.create;
  EGroups:=TStringList.create;
  EActions:=TStringList.create;
  ESounds:=TStringList.create;
  Download:=TStringList.create;
  Uploads:=TStringList.create;
  IconMain.picture.icon.assign(application.icon);
  Initialize;
  screens[11]:=false; //autotyper
  //Load playlist on first creation
  try
    filename := Datawell.TableGlobals.fieldbyname('S24').asstring;
    if fileExists(filename) then
       Datawell.playlist.loadfromfile(filename)
    else Datawell.playlist.Clear;
  except
    on EFOpenError do ;
  end;
  if Datawell.playlist.count > 0 then begin
    Datawell.playindex:=0;
    PlayMusic(Datawell.playlist[Datawell.playindex],true);
  end
  else Datawell.playindex:=-1;
  UpdateMusic;
end;

procedure TFormMain.FormDestroy(Sender: TObject);
begin
   FTickers.Free;
   inherited;
end;

procedure TFormMain.FormActivate(Sender: TObject);
begin
  if Datawell.GotData then exit;
  if Datawell.DataFailed then exit;
  if CheckDebug.visible then exit;
  TimerGrabData.enabled:=false;
  TimerGrabData.enabled:=true;
end;

procedure TFormMain.WMSysCommand(var Message: TWMSysCommand);
begin
  if (Message.CmdType and $FFF0 = SC_MINIMIZE) and (application.active) then
    application.minimize
  else inherited;
end;

procedure TFormMain.WMGetMinMaxInfo(var MSG: Tmessage);
begin
  inherited;
  with PMinMaxInfo(MSG.lparam)^ do begin
    with ptMinTrackSize do begin
      X := 400;
      Y := 300;
    end;
    with ptMaxTrackSize do begin
      X := 9999;
      Y := 9999;
    end;
  end;
end;

procedure TFormMain.EditSendEnter(var Key: Char; sels, sell: integer);
var
  sending: string;
begin
  Datawell.idle:=0;
  key:=#0;
  if Datawell.TableOptions2.fieldbyname('Truncate').asboolean then begin
    EditSend.text:=copy(EditSend.text,1,sels+sell);
    if sell <> 0 then EditSend.text:=copy(EditSend.text,sels+1,99999);
  end;
  if (sels = 0) and (sell > 0) and (sell < length(EditSend.text)) then
    sending:=copy(EditSend.text,1,sell)
  else sending:=EditSend.text;
  if (shifting) and (Datawell.TableOptions3.fieldbyname('L14').asboolean) then
    sending:='"'+sending;
  if ListHistory.visible then begin
    EditSend.selectall;
    CloseHistory;
    exit;
  end;
  if EditHistory.visible then
    ClearHistoryVars;
  AddKeyhistory(sending);
  if recording then
    RecordMacro(sending);
  ParseMain(sending,1);
  CheckRetain;
  homed:=false;
end;

procedure TFormMain.EditSendKeyPress(Sender: TObject; var Key: Char);
var
  work, work2: string;
  i, wl, selStart, selLen: integer;
  didfind: boolean;
begin
  ParsingI:=Parsing.count-1;
  ParsePos:=0;
  if EditSend.text = '' then
   homed:=false;
  selStart:=EditSend.selstart;
  selLen:=EditSend.sellength;
  if key = #13 then
    EditSendEnter(key, selStart, selLen)
  else if Datawell.TableOptions3.fieldbyname('L53').asboolean then begin
    //Active keyhistory
    if key <> #8 then begin //#8 = BACKSPACE
      if homed then begin
        homed:=false;
        exit;
      end;
      if (selStart = 0) and ((selLen > 0) or (EditSend.text = '')) then begin
        work:=copy(EditSend.text,1,selLen) + key;
        wl:=length(work);
        key:=#0;
        didfind:=false;
        work2:=Datawell.SearchWell(work);
        if work2 <> '' then begin
          bypass:=true;
          EditSend.text:=work2;
          EditSend.selstart:=0;
          EditSend.sellength:=wl;
          bypass:=false;
          didfind:=true;
        end;
        if not didfind then begin
          i:=History.count-1;
          while i > 0 do begin
            if work = copy(History[i],1,wl) then begin
              bypass:=true;
              EditSend.text:=History[i];
              EditSend.selstart:=0;
              EditSend.sellength:=wl;
              bypass:=false;
              didfind:=true;
              break;
            end;
            dec(i);
          end;
        end;
        if not didfind then begin
          EditSend.text:=work;
          EditSend.selstart:=length(EditSend.text);
        end;
      end;
    end
    else if key = #8 then begin
      if (selLen > 0) and (selStart = 0) then begin
        EditSend.text:='';
        key:=#0;
      end;
    end;
    homed:=false;
  end;
end;

function TFormMain.DoDelaying(data: string): boolean;
begin
  result:=false;
  if not globaldelay then exit;
  if (Sends.count > 0) or (TimerSend.enabled) then begin
    Sends.add('|P|'+Datawell.TableOptions.fieldbyname('Activator').asstring+data);
    UpdateLabelBuffered;
    result:=true;
  end;
end;

procedure TFormMain.ParseMain(data: string; kind: integer);
var mustParse: boolean;
begin
  Scripts.CurrentContext := kind;
  case kind of
     1: if Datawell.TableOptions.fieldbyname('NTyped').asboolean then data:=Datawell.Nick(data);
     2: if Datawell.TableOptions.fieldbyname('NAutotyper').asboolean then data:=Datawell.Nick(data);
     3: if Datawell.TableOptions.fieldbyname('NAliases').asboolean then data:=Datawell.Nick(data);
     4: if Datawell.TableOptions.fieldbyname('NMacros').asboolean then data:=Datawell.Nick(data);
     5: if Datawell.TableOptions.fieldbyname('NEvents').asboolean then data:=Datawell.Nick(data);
     6: if Datawell.TableOptions.fieldbyname('NPasted').asboolean then data:=Datawell.Nick(data);
     7: if Datawell.TableOptions.fieldbyname('NQuickchars').asboolean then data:=Datawell.Nick(data);
     9: if Datawell.TableOptions.fieldbyname('NTicker').asboolean then data:=Datawell.Nick(data);
    10: if Datawell.TableOptions.fieldbyname('NParsed').asboolean then data:=Datawell.Nick(data);
    11: if Datawell.TableOptions3.fieldbyname('L3').asboolean then data:=Datawell.Nick(data);
  end;
  inc(commandsdone);
  if commandsdone > CommandsMax then begin
    PanelLeftBar.color:=clred;
    abort;
  end;
  if (copy(data,1,1) = '"') and (Datawell.TableOptions3.fieldbyname('L14').asboolean) then begin
    if (kind = 1) and (data <> '') then lastcommand:=data;
    SendData(data,kind);
    exit;
  end;
  if (copy(data,1,1) = ',') and (Datawell.TableOptions3.fieldbyname('L54').asboolean) then begin
    //Forced
    delete(data,1,1);
    if (kind = 1) and (data <> '') then lastcommand:=data;
    systemtext('Forced: '+data,0);
    if (Datawell.connected) or (BtnMUD2.down and Datawell.connected2) then begin
      if BtnMUD1.down then Telnet.SendStr(data+Datawell.cr)
      else Telnet2.SendStr(data+Datawell.cr2);
    end;
    exit;
  end;
  if copy(data,1,3) = '|P|' then begin
    delete(data,1,3);
    globaldelay:=false;
  end
  else globaldelay:=true;
  mustParse:=true;
  if kind in [2, 6] then begin
    if copy(data,1,1) = '%' then delete(data,1,1)
    else mustParse:=false;
  end;
  if mustParse then begin
    if ParseCharting(data,kind) then exit;
    if TryAliasMacro(data,kind) then exit;
    if copy(data,1,1) = Datawell.TableOptions.fieldbyname('Activator').asstring then begin
      delete(data,1,1);
      if ParseSecondary(data) then exit;
      if ParseJumpstart(data) then exit;
      if ParseSystem(data) then exit;
      if ParseSprint(data) then exit;
      if ParseAutotype(data) then exit;
      if ParsePassword(data) then exit;
      if ParseAlias(data) then exit;
      if ParseMacro(data) then exit;
      if ParseQuickchar(data) then exit;
      if ParseNickname(data) then exit;
      if ParseTicker(data) then exit;
      if ParseEvent(data) then exit;
      if ParseGroup(data) then exit;
      if ParseVariables(data) then exit;
      if ParseFile(data) then exit;
      if ParseCanvas(data) then exit;
      if ParseProcess(data) then exit;
      if ParseLogic(data,kind) then exit;
      if ParseRepeat(data) then exit;
      if ParseLastCommand(data,kind) then exit;
      if ParseCycling(data,kind) then exit;
      if ParseParsing(data,kind) then exit;
      if ParseActions(data,kind) then exit;
    end;
  end;
  if (kind = 1) and (data <> '') then lastcommand:=data;
  SendData(data,kind);
end;

procedure TFormMain.SendData(str: string; kind: integer);
var
  linked, suppress, dovar, dofun, dodelay: boolean;
  map, map2, fstr, bstr, dobang, showcolor: string;
  form: TFormWarnMove;
  x, y, x2, y2, p: integer;
begin
//Check for a warning when sprinting
//'|WARN|map|x|y|map2|x2|y2|warning'
  if copy(str,1,6) = '|WARN|' then begin
    delete(str,1,6);
    p:=pos('|',str);
    map:=copy(str,1,p-1);
    delete(str,1,p);
    p:=pos('|',str);
    x:=Datawell.toint(copy(str,1,p-1));
    delete(str,1,p);
    p:=pos('|',str);
    y:=Datawell.toint(copy(str,1,p-1));
    delete(str,1,p);
    p:=pos('|',str);
    map2:=copy(str,1,p-1);
    delete(str,1,p);
    p:=pos('|',str);
    x2:=Datawell.toint(copy(str,1,p-1));
    delete(str,1,p);
    p:=pos('|',str);
    y2:=Datawell.toint(copy(str,1,p-1));
    delete(str,1,p);
    FormMap.SetXY(map,x,y);
    form:=TFormWarnMove.create(self);
    form.EditWarn.text:=str;
    form.showmodal;
    linked:=form.linked;
    form.free;
    if not linked then begin
      FormMap.SetXY(map2,x2,y2);
      ClearSending;
      abort;
    end;
    with FormMap do SetXY(ultimatemap,ultimatex,ultimatey);
    exit;
  end;
  if copy(str,1,3) = 'REM' then exit;
  showcolor:=' ';
  dobang:=' ';
  suppress:=false;
  dovar:=false;
  dofun:=false;
  dodelay:=false;
  fstr:='  '; bstr:='  ';
  if Downloading then exit;
  if PanelDownload.visible then suppress:=true
  else if (copy(str,1,1) = '"') and (kind > 0) and
    (Datawell.TableOptions3.fieldbyname('L14').asboolean) then begin
    delete(str,1,1);
    suppress:=true;
  end;
  case kind of
    1: begin //Typed
         dovar:=Datawell.TableOptions2.fieldbyname('VTyped').asboolean;
         dofun:=Datawell.TableOptions2.fieldbyname('FTyped').asboolean;
         dodelay:=Datawell.TableOptions.fieldbyname('DTyped').asboolean;
         if Datawell.TableOptions2.fieldbyname('BTyped').asboolean then dobang:='!';
         if Datawell.TableOptions.fieldbyname('Typed').asboolean then showcolor:='*';
         fstr:=inttostr(Datawell.TableOptions.fieldbyname('FColorTyped').asinteger);
         bstr:=inttostr(Datawell.TableOptions.fieldbyname('BColorTyped').asinteger);
       end;
    2: begin //Autotyped
         dovar:=Datawell.TableOptions2.fieldbyname('VAutotyped').asboolean;
         dofun:=Datawell.TableOptions2.fieldbyname('FAutotyped').asboolean;
         dodelay:=Datawell.TableOptions.fieldbyname('DAutotyper').asboolean;
         if Datawell.TableOptions2.fieldbyname('BAutotyped').asboolean then dobang:='!';
         if Datawell.TableOptions.fieldbyname('Autotyper').asboolean then showcolor:='*';
         fstr:=inttostr(Datawell.TableOptions.fieldbyname('FColorAutotyper').asinteger);
         bstr:=inttostr(Datawell.TableOptions.fieldbyname('BColorAutotyper').asinteger);
       end;
    3: begin //Alias
         dovar:=Datawell.TableOptions2.fieldbyname('VAliases').asboolean;
         dofun:=Datawell.TableOptions2.fieldbyname('FAliases').asboolean;
         dodelay:=Datawell.TableOptions.fieldbyname('DAliases').asboolean;
         if Datawell.TableOptions2.fieldbyname('BAliases').asboolean then dobang:='!';
         if Datawell.TableOptions.fieldbyname('Aliases').asboolean then showcolor:='*';
         fstr:=inttostr(Datawell.TableOptions.fieldbyname('FColorAliases').asinteger);
         bstr:=inttostr(Datawell.TableOptions.fieldbyname('BColorAliases').asinteger);
       end;
    4: begin //Macro
         dovar:=Datawell.TableOptions2.fieldbyname('VMacros').asboolean;
         dofun:=Datawell.TableOptions2.fieldbyname('FMacros').asboolean;
         dodelay:=Datawell.TableOptions.fieldbyname('DMacros').asboolean;
         if Datawell.TableOptions2.fieldbyname('BMacros').asboolean then dobang:='!';
         if Datawell.TableOptions.fieldbyname('Macros').asboolean then showcolor:='*';
         fstr:=inttostr(Datawell.TableOptions.fieldbyname('FColorMacros').asinteger);
         bstr:=inttostr(Datawell.TableOptions.fieldbyname('BColorMacros').asinteger);
       end;
    5: begin //Events
         dovar:=Datawell.TableOptions2.fieldbyname('VEvents').asboolean;
         dofun:=Datawell.TableOptions2.fieldbyname('FEvents').asboolean;
         dodelay:=Datawell.TableOptions.fieldbyname('DEvents').asboolean;
         if Datawell.TableOptions2.fieldbyname('BEvents').asboolean then dobang:='!';
         if Datawell.TableOptions.fieldbyname('Events').asboolean then showcolor:='*';
         fstr:=inttostr(Datawell.TableOptions.fieldbyname('FColorEvents').asinteger);
         bstr:=inttostr(Datawell.TableOptions.fieldbyname('BColorEvents').asinteger);
       end;
    6: begin //Pasted
         dovar:=Datawell.TableOptions2.fieldbyname('VPasted').asboolean;
         dofun:=Datawell.TableOptions2.fieldbyname('FPasted').asboolean;
         dodelay:=Datawell.TableOptions.fieldbyname('DPasted').asboolean;
         if Datawell.TableOptions2.fieldbyname('BPasted').asboolean then dobang:='!';
         if Datawell.TableOptions.fieldbyname('Pasted').asboolean then showcolor:='*';
         fstr:=inttostr(Datawell.TableOptions.fieldbyname('FColorPasted').asinteger);
         bstr:=inttostr(Datawell.TableOptions.fieldbyname('BColorPasted').asinteger);
       end;
    7: begin //Quickchars
         dovar:=Datawell.TableOptions2.fieldbyname('VQuickchars').asboolean;
         dofun:=Datawell.TableOptions2.fieldbyname('FQuickchars').asboolean;
         dodelay:=Datawell.TableOptions.fieldbyname('DQuickchars').asboolean;
         if Datawell.TableOptions2.fieldbyname('BQuickchars').asboolean then dobang:='!';
         if Datawell.TableOptions.fieldbyname('EQuickchars').asboolean then showcolor:='*';
         fstr:=inttostr(Datawell.TableOptions.fieldbyname('FColorQuickchars').asinteger);
         bstr:=inttostr(Datawell.TableOptions.fieldbyname('BColorQuickchars').asinteger);
       end;
    9: begin //Ticker
         dovar:=Datawell.TableOptions2.fieldbyname('VTicker').asboolean;
         dofun:=Datawell.TableOptions2.fieldbyname('FTicker').asboolean;
         dodelay:=Datawell.TableOptions.fieldbyname('DTicker').asboolean;
         if Datawell.TableOptions2.fieldbyname('BTicker').asboolean then dobang:='!';
         if Datawell.TableOptions.fieldbyname('Eticker').asboolean then showcolor:='*';
         fstr:=inttostr(Datawell.TableOptions.fieldbyname('FColorTicker').asinteger);
         bstr:=inttostr(Datawell.TableOptions.fieldbyname('BColorTicker').asinteger);
       end;
   10: begin //Parsed Commands
         dovar:=Datawell.TableOptions2.fieldbyname('VParsed').asboolean;
         dofun:=Datawell.TableOptions2.fieldbyname('FParsed').asboolean;
         dodelay:=Datawell.TableOptions.fieldbyname('DParsed').asboolean;
         if Datawell.TableOptions2.fieldbyname('BParsed').asboolean then dobang:='!';
         if Datawell.TableOptions.fieldbyname('EParsed').asboolean then showcolor:='*';
         fstr:=inttostr(Datawell.TableOptions.fieldbyname('FColorParsed').asinteger);
         bstr:=inttostr(Datawell.TableOptions.fieldbyname('BColorParsed').asinteger);
       end;
   11: begin //Charted Commands
         dovar:=Datawell.TableOptions3.fieldbyname('L8').asboolean;
         dofun:=Datawell.TableOptions3.fieldbyname('L9').asboolean;
         dodelay:=Datawell.TableOptions3.fieldbyname('L12').asboolean;
         if Datawell.TableOptions3.fieldbyname('L11').asboolean then dobang:='!';
         if Datawell.TableOptions3.fieldbyname('L6').asboolean then showcolor:='*';
         fstr:=inttostr(Datawell.TableOptions3.fieldbyname('I5').asinteger);
         bstr:=inttostr(Datawell.TableOptions3.fieldbyname('I6').asinteger);
       end;
  888: begin //Uploaded files
         suppress:=true;
         showcolor:=' ';
         dodelay:=Datawell.TableOptions2.fieldbyname('DelayUpload').asboolean;
       end;
  999: begin //Delayed & System Text (for login scripts)
         suppress:=true;
         showcolor:='*';
         str:=Datawell.specialcode2+str;
         fstr:=inttostr(Datawell.TableOptions.fieldbyname('FColorSystem').asinteger);
         bstr:=inttostr(Datawell.TableOptions.fieldbyname('BColorSystem').asinteger);
       end;
  end;
  if not suppress then begin
    if dofun then str:=Datawell.ReplaceFunctions(str);
    if dovar then str:=Datawell.ReplaceVariables(str);
    if Datawell.TableOptions2.fieldbyname('PCorrect').asboolean then str:=Datawell.CorrectPunctuation(str);
  end
  else dobang:=' ';
  if length(fstr) = 1 then fstr:=' '+fstr;
  if length(bstr) = 1 then bstr:=' '+bstr;
  str:=dobang+showcolor+fstr+bstr+str;
  if (dodelay) and (Datawell.TableOptions2.fieldbyname('PastedDelay').asinteger > 0) then
    Sends.add('D     <delay>');
  Sends.add(str);
  UpdateLabelBuffered;
  if (not Datawell.connected) and (not Datawell.connected2) and
    (not Datawell.workingoffline) then exit;
  if not doingsend then begin
    doingsend:=true;
    DoSend;
  end;
end;

procedure TFormMain.DoSend;
var
  delay, p, fcol, bcol, len: integer;
  addbang, doshow, dodelay, cronly: boolean;
  work, pass, showmask: string;
begin
  if Datawell.abortdata then exit;
  while Sends.count > 0 do begin
    delay:=0;
    cronly:=false;
    showmask:='';
    work:=Sends[0];
    Sends.delete(0);
    UpdateLabelBuffered;
    if copy(work,1,3) = '|P|' then begin
      ParseMain(work,1);
      continue;
    end;
    addbang := copy(work,1,1) = '!';
    dodelay := copy(work,1,1) = 'D';;
    doshow := copy(work,2,1) = '*';
    if doshow then begin
      fcol:=Datawell.toint(copy(work,3,2));
      bcol:=Datawell.toint(copy(work,5,2));
    end
    else begin
      fcol := 0;
      bcol := 0;
    end;
    delete(work,1,6);
    if copy(work,1,length(Datawell.specialcode2)) = Datawell.specialcode2 then begin
      delete(work,1,length(Datawell.specialcode2));
      len:=length(work);
      if lowercase(copy(work,len-3,4)) = '<cr>' then begin
        delete(work,len-3,4);
        cronly:=true;
      end;
      work:=Datawell.subs('MUD',Telnet.host+' '+Telnet.port,work);
      work:=Datawell.subs('PLAYER',lowercase(Datawell.player),work);
      if pos('PASSWORD2',work) > 0 then begin
        pass:=Datawell.password2;
        if pass = '<NIL>' then pass:='';
        work:=Datawell.subs('PASSWORD2',pass,work);
        showmask:='PASSWORD2';
      end
      else if pos('PASSWORD',work) > 0 then begin
        pass:=Datawell.password;
        if pass = '<NIL>' then pass:='';
        work:=Datawell.subs('PASSWORD',pass,work);
        showmask:='PASSWORD';
      end;
      if work = '' then showmask:='(Empty Line)';
    end;
    if copy(work,1,4) = 'wait' then
      delay:=Datawell.ToInt(copy(work,5,9999))
    else if copy(work,1,5) = 'rwait' then
      delay:=random(Datawell.ToInt(copy(work,6,9999)))+1;
    if dodelay then delay:=1;
    if delay > 0 then begin
      if delay > maxdelay then delay:=maxdelay;
      delaycounter:=delay;
      LabelDelay.caption:=inttostr(delaycounter);
      LabelDelay.show;
      p:=(delay mod 8);
      if p = 0 then p:=8;
      clockphase:=9-p;
      case p of
        1: ImageClock2.show;
        2: ImageClock3.show;
        3: ImageClock4.show;
        4: ImageClock5.show;
        5: ImageClock6.show;
        6: ImageClock7.show;
        7: ImageClock8.show;
        8: ImageClock1.show;
      end;
      if dodelay then TimerSend.interval:=Datawell.TableOptions2.fieldbyname('PastedDelay').asinteger
      else TimerSend.interval:=delay*1000;
      TimerSend.enabled:=true;
      TimerDelay.enabled:=true;
      exit;
    end;
    if addbang then work:='!'+work;
    TimerSend.enabled:=false;
    TimerDelay.enabled:=false;
    LabelDelay.hide;
    HideClocks;
    clockphase:=0;
    if doshow then begin
      if showmask = '' then showmask:=work;
      if Datawell.TableOptions3.fieldbyname('L32').asboolean then
        showmask:=Datawell.subs(Datawell.Password,'<*****>',showmask);
      MUDAnsi.InsertFormatedText(fcol,bcol,showmask+#10,false,false);
    end;
    if (Datawell.connected) or (BtnMUD2.down and Datawell.connected2) then begin
      if cronly then begin
        if BtnMUD1.down then Telnet.SendStr(work+#13)
        else Telnet2.SendStr(work+#13)
      end
      else begin
        if BtnMUD1.down then Telnet.SendStr(work+Datawell.cr)
        else Telnet2.SendStr(work+Datawell.cr2);
      end;
    end;
  end;
  UpdateTotalLabel;
  doingsend:=false;
end;

procedure TFormMain.TimerSendTimer(Sender: TObject);
begin
  TimerSend.enabled:=false;
  DoSend;
end;

function TFormMain.ParseFile(data: string): boolean;
var
  fname: string;
begin
  result:=false;
  if copy(data,1,5) <> 'file ' then exit;
  result:=true;
  if DoDelaying(data) then exit;
  delete(data,1,5);
  if data = '' then begin
    SystemText('Format is: '+Datawell.TableOptions.fieldbyname('Activator').asstring+'file <filename>',0);
    exit;
  end;
  fname:=Datawell.subs('/','\',data);
  if not fileexists(fname) then begin
    if fileexists(fname+'.txt') then fname:=fname+'.txt'
    else begin
      fname:=Datawell.exedir+'\'+fname;
      if not fileexists(fname) then begin
        if fileexists(fname+'.txt') then fname:=fname+'.txt'
        else begin
          SystemText('File does not exist: '+data,0);
          exit;
        end;
      end;
    end;
  end;
  SendFile(fname);
end;

function TFormMain.ParseCanvas(data: string): boolean;
var
  fname: string;
begin
  result:=false;
  if copy(data,1,6) <> 'canvas' then exit;
  result:=true;
  if DoDelaying(data) then exit;
  delete(data,1,6);
  if data = '' then begin
    if not screens[10] then LoadScreen(10)
    else SystemText('The canvas is already open',0);
    exit;
  end;
  if copy(data,1,1) <> ' ' then begin
    result:=false;
    exit;
  end;
  delete(data,1,1);
  if data = '' then begin
    SystemText('Format is: '+Datawell.TableOptions.fieldbyname('Activator').asstring+'canvas <filename>',0);
    exit;
  end;
  if not screens[10] then LoadScreen(10);
  fname:=Datawell.subs('/','\',data);
  if not fileexists(fname) then begin
    if fileexists(fname+'.canvas') then fname:=fname+'.canvas'
    else begin
      fname:=Datawell.exedir+'\'+fname;
      if not fileexists(fname) then begin
        if fileexists(fname+'.canvas') then fname:=fname+'.canvas'
        else begin
          SystemText('File does not exist: '+data,0);
          exit;
        end;
      end;
    end;
  end;
  screenCanvas.gfile:=data;
  screenCanvas.MenuImportClick(nil);
end;

procedure TFormMain.SendFile(fname: string);
var
  cmds: TStringList;
  i: integer;
  failed: boolean;
begin
  failed:=false;
  cmds:=TStringList.create;
  try cmds.loadfromfile(fname); except on EFOpenError do failed:=true; end;
  if failed then exit;
  if cmds.count < 1 then begin
    systemtext('No commands in file: '+fname,0);
    exit;
  end;
  systemtext('Sending file: '+fname,0);
  systemtext('    Commands: '+inttostr(cmds.count),0);
  for i:=0 to cmds.count-1 do ParseMain(cmds[i],6);
  cmds.free;
end;

procedure TFormMain.AddKeyhistory(data: string);
var
  i: integer;
begin
  if length(data) < Datawell.TableOptions.fieldbyname('Chars').asinteger then exit;
  if (History.count > 1) and (History[History.count-1] = data) then exit;
  if pos(Datawell.Password,data) > 0 then exit;
  ClearHistoryVars;
  //Smart Keyhistory
  if (Datawell.TableOptions3.fieldbyname('L55').asboolean) and
    (not Datawell.TableOptions.fieldbyname('FRetain').asboolean) and
    (not Datawell.TableOptions.fieldbyname('RetainAll').asboolean) then begin
    if 1 = 1 then begin
      i:=0;
      while i < History.count do begin
        if History[i] = data then History.delete(i)
        else inc(i);
      end;
    end;
  end;
  History.add(data);
  if History.count > Datawell.TableOptions.fieldbyname('History').asinteger then History.delete(0);
  HistoryI:=History.count;
end;

procedure TFormMain.MacroMasterClick(Sender: TObject);
var work: string;
begin
  if TMenuItem(sender).caption = 'F7' then begin
    if not Datawell.CheckRinged(false,'Instant spellcheck/thesarus') then exit;
    if length(EditSend.text) < 1 then exit;
    if (EditSend.sellength > 1) and (EditSend.sellength < length(EditSend.text)) then
      EditSend.text:=copy(EditSend.text,EditSend.selstart,EditSend.sellength);
    if EditSend.selstart = length(EditSend.text) then
      EditSend.selstart:=length(EditSend.text)-1;
    work:=EditSend.text;
{    Spell.CheckWinControl(EditSend,ctfromcursor);
    if (work = EditSend.text) and (not Spell.checkcanceled) then
      systemtext('Spelling correct',0);}
    if visible then EditSend.setfocus;
    EditSend.sellength:=0;
    EditSend.selstart:=length(EditSend.text);
    exit;
  end
  else if TMenuItem(sender).caption = 'Shift+F7' then begin
    if not Datawell.CheckRinged(false,'Instant spellcheck/thesarus') then exit;
    if length(EditSend.text) < 1 then exit;
    if (EditSend.sellength > 1) and (EditSend.sellength < length(EditSend.text)) then
      EditSend.text:=copy(EditSend.text,EditSend.selstart,EditSend.sellength);
    if EditSend.selstart = length(EditSend.text) then
      EditSend.selstart:=length(EditSend.text)-1;
//    Thesaurus.LookupWinControl(EditSend);
    if visible then EditSend.setfocus;
    EditSend.sellength:=0;
    EditSend.selstart:=length(EditSend.text);
    exit;
  end
  else if TMenuItem(sender).caption = 'Alt+F4' then begin
    if Datawell.TableOptions.fieldbyname('AltF4ToClose').asboolean then begin
      close;
      exit;
    end;
  end;
  if TMenuItem(sender).caption = 'Alt+F6' then exit;
  if recording then begin
    messagedlg('Recording',mtinformation,[mbok],0);
    exit;
  end;
  DoMacro(TMenuItem(sender).caption,0,false);
end;

procedure TFormMain.RetrieveHistory;
begin
  bypass:=true;
  EditSend.text:=History[HistoryI];
  bypass:=false;
  if Datawell.TableOptions.fieldbyname('HighlightKeyhistory').asboolean then EditSend.selectall
  else EditSend.selstart:=length(EditSend.text);
  homed:=true;
  if HistorySearch = '' then begin
    DisplayHistory('History: -'+inttostr(History.count-HistoryI),clwhite);
  end
  else begin
    DisplayHistory('(-'+inttostr(History.count-HistoryI)+') Found: '+HistorySearch,claqua)
  end;
end;

procedure TFormMain.DisplayHistory(str: string; col: TColor);
begin
  EditHistory.text:=str;
  EditHistory.color:=col;
  if col = clwhite then EditHistory.width:=85
  else if col = clyellow then EditHistory.width:=123
  else EditHistory.width:=PanelBars.width-1;
  EditHistory.show;
  TimerHistory.enabled:=false;
  TimerHistory.enabled:=true;
end;

procedure TFormMain.SearchHistory(dir: string);
var
  found: boolean;
  work: string;
begin
  found:=false;
  if dir = 'back' then begin
    if HisB then begin
      if EditHistory.text <> 'No matches found' then EditHistory.color:=clteal;
      exit;
    end;
    if HistoryI = 0 then begin
      HisB:=true;
      DisplayHistory('No matches',clyellow);
      if Datawell.TableOptions.fieldbyname('HighlightKeyhistory').asboolean then EditSend.selectall
      else EditSend.selstart:=length(EditSend.text);
      homed:=true;
      exit;
    end;
    dec(HistoryI);
    for HistoryI:=HistoryI downto 0 do begin
      if copy(History[HistoryI],1,length(HistorySearch)) = HistorySearch then begin
        found:=true;
        break;
      end;
    end;
    if found then begin
      RetrieveHistory;
      if HistoryI = 0 then begin
        HisB:=true;
      end;
    end
    else begin
      HisB:=true;
      work:=Datawell.SearchWell(HistorySearch);
      if work <> '' then begin
        DisplayHistory('Well: '+work,claqua);
        bypass:=true;
        EditSend.text:=work;
        bypass:=false;
        if Datawell.TableOptions.fieldbyname('HighlightKeyhistory').asboolean then EditSend.selectall
        else EditSend.selstart:=length(EditSend.text);
        exit;
      end;
      if EditHistory.visible then begin
        EditHistory.color:=clteal;
      end
      else begin
        DisplayHistory('No matches found',clyellow);
        if Datawell.TableOptions.fieldbyname('HighlightKeyhistory').asboolean then EditSend.selectall
        else EditSend.selstart:=length(EditSend.text);
      end;
    end;
  end
  else begin
    if EditHistory.visible = false then begin
      exit;
    end;
    HisB:=false;
    if HistoryI = History.count-1 then begin
      ClearHistoryVars;
      bypass:=true;
      EditSend.text:='';
      bypass:=false;
      exit;
    end;
    inc(HistoryI);
    for HistoryI:=HistoryI to History.count-1 do begin
      if copy(History[HistoryI],1,length(HistorySearch)) = HistorySearch then begin
        found:=true;
        break;
      end;
    end;
    if found then begin
      RetrieveHistory;
      if HistoryI = History.count then begin
        ClearHistoryVars;
        bypass:=true;
        EditSend.text:='';
        bypass:=false;
      end;
    end
    else begin
      ClearHistoryVars;
      bypass:=true;
      EditSend.text:='';
      bypass:=false;
    end;
  end;
end;

procedure TFormMain.ClearHistoryVars;
begin
  EditHistory.text:='';
  EditHistory.hide;
  HistorySearch:='';
  HisB:=false;
  HistoryI:=History.count;
  TimerHistory.enabled:=false;
end;

procedure TFormMain.MenuShowTellClick(Sender: TObject);
begin
  case TMenuItem(sender).tag of
    1: begin
         if (tabbing) and (not screens[1]) then exit;
         LoadScreen(1);
         screenTell.bringtofront;
         if tabbing then begin
           tabbing:=false;
           abort;
         end;
       end;
    2: begin
         if (tabbing) and (not screens[2]) then exit;
         LoadScreen(2);
         screenRoom.bringtofront;
         if tabbing then begin
           tabbing:=false;
           abort;
         end;
       end;
    3: begin
         if (tabbing) and (not screens[4]) then exit;
         LoadScreen(4);
         screenImagery.bringtofront;
         if tabbing then begin
           tabbing:=false;
           abort;
         end;
       end;
    6: begin
         if (tabbing) and (not screens[0]) then exit;
         LoadScreen(0);
         screenChat.bringtofront;
         if tabbing then begin
           tabbing:=false;
           abort;
         end;
       end;
    7: begin
         if (tabbing) and (not screens[6]) then exit;
         LoadScreen(6);
         screenFiltered.bringtofront;
         if tabbing then begin
           tabbing:=false;
           abort;
         end;
       end;
    9: begin
         if (tabbing) and (not FormMap.visible) then exit;
         FormMap.show;
         FormMap.windowstate:=wsnormal;
         FormMap.bringtofront;
         MenuShowCartographer.checked:=true;
         if tabbing then begin
           tabbing:=false;
           abort;
         end;
       end;
    14: begin
         if (tabbing) and (not screens[10]) then exit;
         LoadScreen(10);
         screenCanvas.bringtofront;
         if tabbing then begin
           tabbing:=false;
           abort;
         end;
       end;
  end;
end;

procedure TFormMain.MenuEventsClick(Sender: TObject);
var
  form: TFormEvents;
  i: integer;
  didfind: boolean;
begin
  didfind:=false;
  with Datawell.TableGroups do begin
    first;
    while not EOF do begin
      if Datawell.TableGroups.fieldbyname('FGroup').asstring = Datawell.lastgroup then begin
        didfind:=true;
        break;
      end;
      next;
    end;
    if not didfind then begin
      first;
      while not EOF do begin
        if Datawell.TableGroups.fieldbyname('FGroup').asstring = 'BASE' then begin
          didfind:=true;
          break;
        end;
        next;
      end;
    end;
    if not didfind then first;
  end;
  form:=TFormEvents.create(self);
  for i:=1 to Datawell.eventpage do form.TabEvents.selectnextpage(true);
  form.showmodal;
  if form.TabEvents.activepage = form.PageEvents then
    Datawell.eventpage:=0 else Datawell.eventpage:=1;
  form.free;
  SetupEvents;
end;

procedure TFormMain.MenuQuickEventClick(Sender: TObject);
var form: TFormEventQ;
begin
  if not Datawell.CheckRinged2('quick events') then exit;
  form:=TFormEventQ.create(self);
  form.showmodal;
  form.free;
  SetupEvents;
end;

procedure TFormMain.MenuAliasesClick(Sender: TObject);
var form: TFormAlias;
begin
  if (recording) and (EditAlias.visible) then begin
    messagedlg('You cannot edit aliases when recording an alias',mtinformation,[mbok],0);
    exit;
  end;
  form:=TFormAlias.create(self);
  form.showmodal;
  form.free;
  PopulateRecord;
end;

procedure TFormMain.MenuMacrosClick(Sender: TObject);
var form: TFormMacros;
begin
  if (recording) and (EditMacro.visible) then begin
    messagedlg('You cannot edit macros when recording a macro',mtinformation,[mbok],0);
    exit;
  end;
  form:=TFormMacros.create(self);
  form.a4.enabled:= not Datawell.TableOptions.fieldbyname('AltF4ToClose').asboolean;
  form.showmodal;
  form.free;
  PopulateRecord;
end;

procedure TFormMain.MenuProgramOptionsClick(Sender: TObject);
var
  form: TFormOptions;
  i: integer;
begin
  form:=TFormOptions.create(self);
  for i:=1 to Datawell.optionpage do form.TabOptions.selectnextpage(true);
  form.ImageHP.picture.bitmap.assign(ImageHP.picture.bitmap);
  form.ImageSP.picture.bitmap.assign(ImageSP.picture.bitmap);
  form.ImageGP1.picture.bitmap.assign(ImageGP1.picture.bitmap);
  form.ImageGP2.picture.bitmap.assign(ImageGP2.picture.bitmap);
  form.ImageEnemy.picture.bitmap.assign(ImageEnemy.picture.bitmap);
  form.BtnEnemy.glyph.assign(ImageEnemy.picture.bitmap);
  form.BtnEnemyLow.glyph.assign(ImageEnemyLow.picture.bitmap);
  form.BtnEnemyMedian.glyph.assign(ImageEnemyMedian.picture.bitmap);
  form.BtnEnemyHigh.glyph.assign(ImageEnemyHigh.picture.bitmap);
  form.BtnEnemyBetter.glyph.assign(ImageEnemyBetter.picture.bitmap);
  form.showmodal;
  UpdateSendbar;
  UpdateToolbar;
  UpdateLED;
  EditSend.wordwrap:=Datawell.TableOptions2.fieldbyname('AutoExpand').asboolean;
  ShowMenu(Datawell.TableOptions.fieldbyname('Menu').asboolean);
  if form.TabOptions.activepage = form.PageMessages then
    Datawell.optionpage:=0
  else if form.TabOptions.activepage = form.PageMedia then
    Datawell.optionpage:=1
  else if form.TabOptions.activepage = form.PageStatusBars then
    Datawell.optionpage:=2
  else if form.TabOptions.activepage = form.PageText then
    Datawell.optionpage:=3
  else if form.TabOptions.activepage = form.PageCommandLine then
    Datawell.optionpage:=4
  else if form.TabOptions.activepage = form.PageKeyhistory then
    Datawell.optionpage:=5
  else if form.TabOptions.activepage = form.PageReversing then
    Datawell.optionpage:=6
  else if form.TabOptions.activepage = form.PageFTP then
    Datawell.optionpage:=7
  else Datawell.optionpage:=8;
  form.free;
  MUDAnsi.linewrap:=Datawell.TableOptions3.fieldbyname('I29').asinteger;
  if MUDAnsi.linewrap < 20 then MUDAnsi.linewrap:=80;
  if MUDAnsi.linewrap > 120 then MUDAnsi.linewrap:=120;
  Scrollback.linewrap:=MUDAnsi.linewrap;
  MUDAnsi.maxlines:=Datawell.TableOptions.fieldbyname('Scroll').asinteger;
  MUDAnsi.Autocopy:=Datawell.TableOptions.fieldbyname('Autocopy').asboolean;
  MUDAnsi.CopyToScrollback:=Datawell.TableOptions.fieldbyname('FeedScrollback').asboolean;
  MUDAnsi.fullflash:=Datawell.TableOptions2.fieldbyname('FullFlash').asboolean;
  Scrollback.fullflash:=Datawell.TableOptions2.fieldbyname('FullFlash').asboolean;
  PanelScrollTop.visible:=Datawell.TableOptions.fieldbyname('ScrollbackLabels').asboolean;
  PanelScrollBottom.visible:=Datawell.TableOptions.fieldbyname('ScrollbackLabels').asboolean;
  UpdateGauge(1,olds[0],true);
  UpdateGauge(2,olds[1],true);
  UpdateGauge(3,olds[2],true);
  UpdateGauge(4,olds[3],true);
  if ImageEnemyBetter.visible then FigureEnemyPercent('101')
  else FigureEnemyPercent(inttostr(GaugeEnemy.progress));
  UpdateHPBars;
  if History.count > Datawell.TableOptions.fieldbyname('History').asinteger then begin
    for i:=1 to History.count-Datawell.TableOptions.fieldbyname('History').asinteger do
      History.delete(0);
  end;
  UpdateTickerLabel;
  MUDAnsi.SelFGColor:=
    Datawell.FigureColor(Datawell.TableOptions.fieldbyname('FColorSelected').asinteger);
  MUDAnsi.SelBGColor:=
    Datawell.FigureColor(Datawell.TableOptions.fieldbyname('BColorSelected').asinteger);
  Scrollback.SelFGColor:=
    Datawell.FigureColor(Datawell.TableOptions.fieldbyname('FColorSelected').asinteger);
  Scrollback.SelBGColor:=
    Datawell.FigureColor(Datawell.TableOptions.fieldbyname('BColorSelected').asinteger);
  UpdateMasks;
  UpdateHyperlinks;
//Update parsing buffer
  while Parsing.count > Datawell.TableOptions3.fieldbyname('I32').asinteger do Parsing.delete(0);
end;

procedure TFormMain.MenuQuickcharsClick(Sender: TObject);
var form: TFormActions;
begin
  form:=TFormActions.create(self);
  form.showmodal;
  form.free;
end;

procedure TFormMain.MUDAnsiCodeReceived(data: string);
var
  p, i1, i2: integer;
  decode, s1, s2, s3, s4: string;
  b1, b2, b3, b4: boolean;
begin
  i1:=0; i2:=0;
  s1:=''; s2:=''; s3:=''; s4:='';
  b1:=false; b2:=false; b3:=false; b4:=false;
  decode:=copy(data,1,3);
  delete(data,1,3);
// FFF-Status Elements
  if decode = 'FFF' then begin
    while length(data) > 0 do begin
      s1:=copy(data,1,1);
      delete(data,1,1);
      if copy(data,1,1) = Datawell.delim then delete(data,1,1);
      if length(data) < 1 then break;
      p:=pos(Datawell.delim,data);
      if p > 0 then begin
        s2:=copy(data,1,p-1);
        delete(data,1,p);
      end
      else begin
        s2:=data;
        data:='';
      end;
      if s1 = 'A' then begin
        if LabelHP.caption <> '' then olds[0]:=Datawell.ToInt(LabelHP.caption);
        LabelHP.caption:=s2; b1:=true;
        UpdateCanvasVariable('@HP',s2);
      end
      else if s1 = 'B' then begin
        if Datawell.ToInt(s2) >= 0 then begin
          LabelHPMax.caption:=s2; b1:=true;
          UpdateCanvasVariable('@MAXHP',s2);
        end;
      end
      else if s1 = 'C' then begin
        if LabelSP.caption <> '' then olds[1]:=Datawell.ToInt(LabelSP.caption);
        LabelSP.caption:=s2; b2:=true;
        UpdateCanvasVariable('@SP',s2);
      end
      else if s1 = 'D' then begin
        if Datawell.ToInt(s2) >= 0 then begin
          LabelSPMax.caption:=s2; b2:=true;
          UpdateCanvasVariable('@MAXSP',s2);
        end;
      end
      else if s1 = 'E' then begin
        if LabelGP1.caption <> '' then olds[2]:=Datawell.ToInt(LabelGP1.caption);
        LabelGP1.caption:=s2; b3:=true;
        UpdateCanvasVariable('@GP1',s2);
      end
      else if s1 = 'F' then begin
        if Datawell.ToInt(s2) >= 0 then begin
          LabelGP1Max.caption:=s2; b3:=true;
          UpdateCanvasVariable('@MAXGP1',s2);
        end;
      end
      else if s1 = 'G' then begin
        if LabelGP2.caption <> '' then olds[3]:=Datawell.ToInt(LabelGP2.caption);
        LabelGP2.caption:=s2; b4:=true;
        UpdateCanvasVariable('@GP2',s2);
      end
      else if s1 = 'H' then begin
        if Datawell.ToInt(s2) >= 0 then begin
          LabelGP2Max.caption:=s2; b4:=true;
          UpdateCanvasVariable('@MAXGP2',s2);
        end;
      end
      else if s1 = 'I' then begin
        SetGLine(s2,1);
        UpdateCanvasVariable('@GLINE1',s2);
      end
      else if s1 = 'J' then begin
        SetGLine(s2,2);
        UpdateCanvasVariable('@GLINE2',s2);
      end
      else if s1 = 'K' then begin
        ImageEnemyName.hint:=s2;
        if screens[4] then begin
          if s2 = '' then screenImagery.LabelText.font.color:=clgray
          else begin
            screenImagery.LabelText.caption:=s2;
            screenImagery.LabelText.font.color:=clblack;
          end;
        end;
        LabelEName.caption:=s2;
        LabelEName2.caption:=s2;
        UpdateCanvasVariable('@ENAME',s2);
      end
      else if s1 = 'L' then begin
        FigureEnemyPercent(s2);
        UpdateCanvasVariable('@ENEMY',inttostr(GaugeEnemy.progress));
      end
      else if s1 = 'M' then begin
        EnemyImage(s2);
      end;
    end;
    if b1 then UpdateGauge(1,olds[0],false);
    if b2 then UpdateGauge(2,olds[1],false);
    if b3 then UpdateGauge(3,olds[2],false);
    if b4 then UpdateGauge(4,olds[3],false);
    firststatus:=true;
  end
// AAA-Sounds
// #K%55555003AAA<filename>
  else if decode = 'AAA' then begin
    if not Datawell.TableOptions3.fieldbyname('L24').asboolean then exit;
    PlaySound(data,1,1,0,false);
  end
// AAB-Images
// #K%55555XXXAAB<filename>~<image label>
  else if decode = 'AAB' then begin
    data:=Datawell.subs('^^',Datawell.delim,data);
    p:=pos(Datawell.delim,data);
    if p > 0 then begin
      s1:=copy(data,1,p-1);
      delete(data,1,p);
      s2:=data;
    end
    else s1:=data;
    ShowImage(s1,s2);
  end
// AAC-Reboot
// #K%55555XXXAAC<reboot string>
  else if decode = 'AAC' then begin
    if data <> '' then rebootstring:='Reboot: '+data
    else rebootstring:='';
    UpdateCaption;
  end
// AAD-MUSIC
// #K%55555XXXAAD<filename>~<iterations>
  else if decode = 'AAD' then begin
    if not Datawell.TableOptions3.fieldbyname('L24').asboolean then exit;
    data:=Datawell.subs('^^',Datawell.delim,data);
    p:=pos(Datawell.delim,data);
    if p > 0 then begin
      s1:=copy(data,1,p-1);
      delete(data,1,p);
      s2:=data;
    end
    else s1:=data;
    if s1 = '' then begin
      MenuMusicPause.click;
      exit;
    end;
    repeatmusic:=Datawell.toint(s2);
    if repeatmusic > 0 then dec(repeatmusic);
    MenuMusicRepeat.checked:=(s2 <> '');
    if MenuMusicRepeat.checked then MenuMusicRandomize.checked:=false;
    //reload playlist
    Datawell.playlist.clear;
    Datawell.playlist.add(s1);
    Datawell.playindex:=0;
    PlayMusic(s1,false);
    UpdateMusic;
  end
// AAE-115 Available
// #K%55555XXXAAE
// AAF-Uptime
// #K%55555XXXAAF<uptime string>
  else if decode = 'AAF' then begin
    if data <> '' then uptimestring:='Uptime: '+data
    else uptimestring:='';
    UpdateCaption;
  end
// AAG-AVI's
// #K%55555XXXAAG<filename>~<image label>~<height>~<width>~<repeat>
  else if decode = 'AAG' then begin
    if not Datawell.TableOptions3.fieldbyname('L24').asboolean then exit;
    data:=Datawell.subs('^^',Datawell.delim,data);
    p:=pos(Datawell.delim,data);
    if p > 0 then begin
      s1:=copy(data,1,p-1);
      delete(data,1,p);
      p:=pos(Datawell.delim,data);
      if p > 0 then begin
        s2:=copy(data,1,p-1);
        delete(data,1,p);
        p:=pos(Datawell.delim,data);
        if p > 0 then begin
          i1:=Datawell.toint(copy(data,1,p-1));
          delete(data,1,p);
          p:=pos(Datawell.delim,data);
          if p > 0 then begin
            i2:=Datawell.toint(copy(data,1,p-1));
            delete(data,1,p);
            b1:=(data <> '');
          end;
        end;
      end
      else s2:=data;
    end
    else s1:=data;
    if s1 = '' then exit;
    ShowAVI(s1,s2,i1,i2,b1);
  end
// AAH-Automatic Download
// #K%55555003AAH<filename>~<URL>
  else if decode = 'AAH' then begin
    if not Datawell.TableOptions3.fieldbyname('L30').asboolean then exit;
    p:=pos(Datawell.delim,data);
    if p > 0 then begin
      s1:=copy(data,1,p-1);
      delete(data,1,p);
      s2:=data;
    end
    else s1:=data;
    DownloadMedia(s1,s2);
  end
// BAA-Combat Special
// #K%55555XXXBAA<combat special string>
  else if decode = 'BAA' then begin
    Special(1,data);
  end
// BAB-Tell Monitor
// #K%55555XXXBAB<is it from me?>~<other person>~<message>
  else if decode = 'BAB' then begin
    if not Datawell.TableOptions3.fieldbyname('L17').asboolean then exit;
    p:=pos(Datawell.delim,data);
    if p > 0 then begin
      s1:=copy(data,1,p-1);
      delete(data,1,p);
      p:=pos(Datawell.delim,data);
      if p > 0 then begin
        s2:=copy(data,1,p-1);
        delete(data,1,p);
        s3:=data;
      end;
    end;
    if (s2 = '') or (s3 = '') then exit;
    Datawell.AddTell(s1,s2,s3);
    if screens[1] then screenTell.ClosePopup;
  end
// BAC-Guilds Special
// #K%55555XXXBAC<guild special string>
  else if decode = 'BAC' then begin
    Special(2,data);
  end
// BAD-Short Room Description
// #K%55555XXXBAD<room short string>
  else if decode = 'BAD' then begin
    roomshortstring:=data;
    LabelStatus.caption:=' '+roomshortstring;
    if not screens[2] then exit;
    screenRoom.PanelShort.caption:=LAbelStatus.caption;
  end
// BAE-Mudlag
// #K%55555XXXBAE<mudlag string>
  else if decode = 'BAE' then begin
    if data <> '' then mudlagstring:='Mudlag: '+data
    else mudlagstring:='';
    UpdateCaption;
  end
// BAF-Edit
// #K%55555XXXBAF<edit string>
  else if decode = 'BAF' then begin
    editingstring:=data;
    if editingstring <> '' then begin
      editingstring:='Editing: '+editingstring;
      LabelStatus.caption:=' '+editingstring;
    end
    else LabelStatus.caption:=' '+roomshortstring;
  end
// BBA-GP1 Mask
// #K%55555XXXBBA<GP1 Mask>
  else if decode = 'BBA' then begin
    Datawell.TableOptions.edit;
    Datawell.TableOptions.fieldbyname('GP1Mask').asstring:=data;
    Datawell.TableOptions.post;
    UpdateMasks;
  end
// BBB-GP2 Mask
// #K%55555XXXBBB<GP2 Mask>
  else if decode = 'BBB' then begin
    Datawell.TableOptions.edit;
    Datawell.TableOptions.fieldbyname('GP2Mask').asstring:=data;
    Datawell.TableOptions.post;
    UpdateMasks;
  end
// BBC-HP Mask
// #K%55555XXXBBC<HP Mask>
  else if decode = 'BBC' then begin
    Datawell.TableOptions2.edit;
    Datawell.TableOptions2.fieldbyname('HPMask').asstring:=data;
    Datawell.TableOptions2.post;
    UpdateMasks;
  end
// BBD-SP Mask
// #K%55555XXXBBD<SP Mask>
  else if decode = 'BBD' then begin
    Datawell.TableOptions2.edit;
    Datawell.TableOptions2.fieldbyname('SPMask').asstring:=data;
    Datawell.TableOptions2.post;
    UpdateMasks;
  end
// CAP-Caption
// #K%55555XXXCAP<caption string>
  else if decode = 'CAP' then begin
    captionstring:=data;
    UpdateCaption;
  end
// CAA-Chat Monitor
// #K%55555XXXCAA<command>~<chat line>~<who chatted>~<message>
  else if decode = 'CAA' then begin
    if not Datawell.TableOptions3.fieldbyname('L1').asboolean then exit;
    p:=pos(Datawell.delim,data);
    if p > 0 then begin
      s1:=copy(data,1,p-1);
      delete(data,1,p);
      p:=pos(Datawell.delim,data);
      if p > 0 then begin
        s2:=copy(data,1,p-1);
        delete(data,1,p);
        p:=pos(Datawell.delim,data);
        if p > 0 then begin
          s3:=copy(data,1,p-1);
          delete(data,1,p);
          s4:=data;
        end;
      end;
    end;
    if (s2 = '') or (s4 = '') then exit;
    Datawell.AddChat(s1,s2,s3,s4);
    if screens[0] then begin
      screenChat.ClosePopup;
      screenChat.UpdateWidths;
    end;
  end
// CDF-Begin Download
// #K%55555XXXCDF4Max~<filename>
  else if decode = 'CDF' then begin
    p:=pos(Datawell.delim,data);
    if p > 0 then begin
      i1:=Datawell.toint(copy(data,1,p-1));
      delete(data,1,p);
      s2:=data;
    end;
    if s2 = '' then exit;
    DownloadMax:=i1;
    if DownloadMax < 1 then DownloadMax:=99999;
    LabelDownload.caption:=s2;
    while pos('/',s2) > 0 do delete(s2,1,pos('/',s2));
    DownloadString:=s2;
    Download.clear;
    DownloadC:=0;
    Downloading:=true;
    LEDDownloadF.bringtofront;
    LEDDownloadF.repaint;
    ImageDownload.hint:='Downloading: '+DownloadString;
    if Datawell.TableOptions3.fieldbyname('L61').asboolean then begin
      MemoCopy.text:=data;
      MemoCopy.selectall;
      MemoCopy.CopyToClipboard;
    end;
    GaugeDownload.progress:=0;
    GaugeDownload.maxvalue:=DownloadMax;
    if (DownloadMax < 20) or (DownloadMax >= 99999) then
      GaugeDownload.backcolor:=clgray
    else GaugeDownload.backcolor:=clnavy;
    PanelDownload.show;
    PanelDownload.repaint;
    UpdateDownloadButtons;
    LabelDownload.repaint;
    BtnCancelDownload.repaint;
  end
// CCF-Get Line for Download
// #K%55555XXXCCF<line of text>
  else if decode = 'CCF' then begin
    if not Downloading then exit;
    data:=Datawell.subs('^^','~',data);
    Download.add(data);
    inc(DownloadC);
    if GaugeDownload.backcolor <> clgray then GaugeDownload.progress:=DownloadC;
    if DownloadC >= DownloadMax then FinishDownload;
  end
// CEF-End Download
// #K%55555003CEF
  else if decode = 'CEF' then begin
    FinishDownload;
  end
// DDD-Room Elements
  else if decode = 'DDD' then begin
    if not screens[2] then exit;
    screenRoom.ProcessCode(lowercase(data));
  end
end;

procedure TFormMain.FinishDownload;
var
  F: TextFile;
  filename: string;
  i: integer;
begin
  if not Downloading then exit;
  Downloading:=false;
  DownloadC:=DownloadMax;
  LEDDownloadT.bringtofront;
  LEDDownloadT.hint:='Download available: '+DownloadString;
  PopupCopyDownloadA.caption:='&Copy "'+DownloadString+'" to Autotyper';
  PopupCaptureDownload.caption:='Capture "'+DownloadString+'" to &file';
  PanelDownload.hide;
  UpdateDownloadButtons;
  if Datawell.TableOptions.fieldbyname('UseLocalDir').asboolean then begin
    filename:=Datawell.TableOptions.fieldbyname('LocalDir').asstring+'\'+DownloadString;
    if (not Datawell.TableOptions.fieldbyname('OverwriteLocalDir').asboolean) and
      (FileExists(filename)) then begin
      exit;
    end;
    try AssignFile(F,filename);
      except on EInOutError do begin
        SystemText('Unable to save file to local directory.  Check Program Option settings.',0);
        exit;
      end;
    end;
    try Rewrite(F);
      except on EInOutError do begin
        SystemText('Unable to save file to local directory.  Check Program Option settings.',0);
        exit;
      end;
    end;
    for i:=0 to Download.count-1 do WriteLn(F,Download[i]);
    CloseFile(F);
  end;
end;

procedure TFormMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  if PanelScroll.height > 0 then BtnCloseScrollback.click;
  if Datawell.connected then begin
    if (not panicclosing) and (Datawell.TableOptions3.fieldbyname('L52').asboolean) then begin
      if messagedlg('Break current connection?',
        mtconfirmation,[mbyes,mbcancel],0) = mrcancel then abort;
    end;
    overrideclose:=true;
    Telnet.close;
    overrideclose:=false;
  end;
  if (Datawell.TableOptions3.fieldbyname('L45').asboolean and Datawell.connected2) then Telnet2.close;
  if screens[11] then begin
    if screenEditor.BtnSaveAll.enabled then screenEditor.show;
    screenEditor.close;
  end;
  if not loginclose then SaveOptions(false);
  DLMedia.free;
  Sends.free;
  Tags.free;
  History.free;
  Parsing.free;
  Sounds.free;
  EEvents.free;
  EGroups.free;
  EActions.free;
  ESounds.free;
  Download.free;
  Uploads.free;
  overrideclose:=true;
  Telnet.Close;
  overrideclose:=false;
  FormLogin.close;
  Application.terminate;
end;

procedure TFormMain.FormResize(Sender: TObject);
begin
  PanelMessageBase.width:=PanelBasebar.width;
  PanelToolbar.width:=PanelBasebar.width;
  PanelStatusbar.width:=PanelBasebar.width;
  EditSend.width:=PanelSend.width+3;
  ImageHP1Bar.width:=PanelBars.width-2;
  ImageHP2Bar.width:=PanelBars.width-2;
  BtnCloseHP1.left:=PanelBars.width-15;
  BtnCloseHP2.left:=PanelBars.width-15;
  BtnCloseHP3.left:=PanelBars.width-15;
  BtnCloseHP4.left:=PanelBars.width-15;
  EditHistory.width:=EditSend.width-1;
  EditSearch.width:=EditSend.width;
  ListHistory.width:=PanelBars.width-14;
  PanelDownload.left:=PanelBars.width-196;
  PanelScrollTop.left:=clientwidth-47;
  PanelScrollBottom.left:=clientwidth-47;
  if PanelScroll.height > PanelLeftBar.height-barbuffer-PanelSend.height then begin
    PanelScroll.height:=PanelLeftBar.height-barbuffer-PanelSend.height;
    Datawell.TableOptions.edit;
    Datawell.TableOptions.fieldbyname('ScrollPosition').asinteger:=PanelScroll.height;
    Datawell.TableOptions.post;
  end;
  UpdateSendbar;
  UpdateScrollbackLabels;
end;

procedure TFormMain.BtnRecordClick(Sender: TObject);
var
  cmds: TStringList;
  didfind: boolean;
begin
  if not MenuShowRecordTool.checked then exit;
  if recording then begin
    TimerRecord.enabled:=false;
    MacroStop.hide;
    MacroRecord.show;
    EditAlias.enabled:=true;
    EditMacro.enabled:=true;
    BtnAli.enabled:=true;
    BtnMac.enabled:=true;
    recording:=false;
    exit;
  end;
  if (not Datawell.connected) and (not Datawell.connected2) then begin
    messagedlg('Not connected to server',mtinformation,[mbok],0);
    exit;
  end;
  if EditMacro.visible then begin
    if EditMacro.text = '' then begin
      messagedlg('Please select a macro first',mtinformation,[mbok],0);
      exit;
    end;
    with Datawell.TableMacros do begin
      didfind:=false;
      first;
      while not EOF do begin
        if fieldbyname('Macro').asstring = EditMacro.text then begin
          didfind:=true;
          break;
        end;
        next;
      end;
      if not didfind then exit;
      cmds:=TStringList.create;
      cmds.assign(fieldbyname('Script'));
      if cmds.count > 0 then begin
        if messagedlg('Macro "'+fieldbyname('Macro').asstring+
          '" has an existing script, overwrite?',
          mtconfirmation,[mbyes,mbno],0) = mrno then begin
          cmds.free;
          exit;
        end;
      end;
      cmds.clear;
      edit;
      fieldbyname('Script').assign(cmds);
      post;
      cmds.free;
    end;
  end
  else begin
    if EditAlias.text = '' then begin
      messagedlg('Please select an alias first',mtinformation,[mbok],0);
      exit;
    end;
    with Datawell.TableAliases do begin
      didfind:=false;
      first;
      while not EOF do begin
        if fieldbyname('Alias').asstring = EditAlias.text then begin
          didfind:=true;
          break;
        end;
        next;
      end;
      if not didfind then exit;
      cmds:=TStringList.create;
      cmds.assign(fieldbyname('Script'));
      if cmds.count > 0 then begin
        if messagedlg('Alias "'+fieldbyname('Alias').asstring+
          '" has an existing script, overwrite?',
          mtconfirmation,[mbyes,mbno],0) = mrno then begin
          cmds.free;
          exit;
        end;
      end;
      cmds.clear;
      edit;
      fieldbyname('Script').assign(cmds);
      post;
      cmds.free;
    end;
  end;
  recording:=true;
  EditAlias.enabled:=false;
  EditMacro.enabled:=false;
  BtnAli.enabled:=false;
  BtnMac.enabled:=false;
  MacroRecord.hide;
  MacroStop.show;
  TimerRecord.interval:=1000;
  TimerRecord.enabled:=true;
  if visible then EditSend.setfocus;
end;

procedure TFormMain.RecordMacro(macro: string);
var cmds: TStringList;
begin
  cmds:=TSTringList.create;
  if EditMacro.visible then begin
    with Datawell.TableMacros do begin
      cmds.assign(fieldbyname('Script'));
      cmds.add(macro);
      edit;
      fieldbyname('Script').assign(cmds);
      post;
    end;
  end
  else begin
    with Datawell.TableAliases do begin
      cmds.assign(fieldbyname('Script'));
      cmds.add(macro);
      edit;
      fieldbyname('Script').assign(cmds);
      post;
    end;
  end;
  if cmds.count >= 500 then begin
    messagedlg('You can only record 500 commands maximum',mtinformation,[mbok],0);
    BtnRecord.click;
  end;
  cmds.free;
  MacroPulse2.bringtofront;
  TimerRecordPulse.enabled:=false;
  TimerRecordPulse.enabled:=true;
end;

procedure TFormMain.LoadOptions;
var
  h, lastversion: integer;
  work: string;
begin
  lastversion:=Datawell.TableOptions3.fieldbyname('I11').asinteger;
  SetupEvents;
//  LEDMidBob.bringtofront;
  LEDBob.bringtofront;
//  PopupBobMe.enabled:=true;
  with Datawell.TableOptions3 do begin
    edit;
    //8702 Stuff
    if lastversion < 8702 then begin
      fieldbyname('L61').asboolean:=true;
    end;
    //8664 Stuff
    if lastversion < 8664 then begin
      fieldbyname('I32').asinteger:=250;
      fieldbyname('I33').asinteger:=4;
      fieldbyname('L58').asboolean:=false;
      fieldbyname('L59').asboolean:=true;
      fieldbyname('L60').asboolean:=true;
      fieldbyname('L31').asboolean:=false;
    end;
    //8006 Stuff
    if lastversion < 8304 then begin
      fieldbyname('I30').asinteger:=0;
      fieldbyname('I31').asinteger:=0;
      fieldbyname('L56').asboolean:=true;
      fieldbyname('L57').asboolean:=false;
    end;
    //8006 Stuff
    if lastversion < 8008 then begin
      fieldbyname('L53').asboolean:=true;
      fieldbyname('L54').asboolean:=true;
      fieldbyname('L55').asboolean:=true;
    end;
    //8000 Stuff
    if lastversion < 7401 then begin
      fieldbyname('S2').asstring:='[36';
      fieldbyname('L49').asboolean:=true;
      fieldbyname('L50').asboolean:=true;
      fieldbyname('L51').asboolean:=false;
      fieldbyname('L52').asboolean:=true;
      fieldbyname('I19').asinteger:=clsilver;
      fieldbyname('I20').asinteger:=clblack;
      fieldbyname('I22').asinteger:=clblack;
    end;
    //6103 Added HP1 Bar font size, use as status colors, exit scrollback
    if lastversion < 6103 then begin
      fieldbyname('I25').asinteger:=10;
      fieldbyname('L43').asboolean:=false;
      fieldbyname('L44').asboolean:=true;
    end;
    //6003 Added background status colors
    if lastversion < 6003 then begin
      fieldbyname('I19').asinteger:=clsilver;
      fieldbyname('I20').asinteger:=clblack;
      fieldbyname('I21').asinteger:=clwhite;
      fieldbyname('I22').asinteger:=clblack;
      fieldbyname('I23').asinteger:=-1;
      fieldbyname('I24').asinteger:=clblack;
      fieldbyname('L42').asboolean:=false;
    end;
    //Set current version on player file (if less than current version)
    if lastversion < Datawell.toint(Datawell.version3) then
      fieldbyname('I11').asinteger:=Datawell.toint(Datawell.version3);
    post;
  end;
  if CheckDebug.visible then Datawell.ptitle:='Notes';
  ShowMenu(Datawell.TableOptions.fieldbyname('Menu').asboolean);
  top:=Datawell.TableOptions.fieldbyname('Top').asinteger;
  left:=Datawell.TableOptions.fieldbyname('FLeft').asinteger;
  height:=Datawell.TableOptions.fieldbyname('Height').asinteger;
  width:=Datawell.TableOptions.fieldbyname('Width').asinteger;
  if Datawell.TableOptions3.fieldbyname('L41').asboolean then windowstate:=wsmaximized;
  work:=Datawell.TableOptions.fieldbyname('FontName').asstring;
  if work = '' then work:='Courier New';
  //Set linewrap
  MUDAnsi.linewrap:=Datawell.TableOptions3.fieldbyname('I29').asinteger;
  if MUDAnsi.linewrap < 20 then MUDAnsi.linewrap:=80;
  Scrollback.linewrap:=MUDAnsi.linewrap;
  MUDAnsi.font.name:=work;
  h:=Datawell.TableOptions.fieldbyname('FontStyle').asinteger;
  MUDAnsi.font.style:=[];
  case h of
    0: MUDAnsi.font.style:=[];
    1: MUDAnsi.font.style:=[fsbold];
    2: MUDAnsi.font.style:=[fsitalic];
    3: MUDAnsi.font.style:=[fsbold, fsitalic];
  end;
  MUDAnsi.font.size:=Datawell.TableOptions.fieldbyname('FontSize').asinteger;
  UpdateFonts;
  MUDAnsi.maxlines:=Datawell.TableOptions.fieldbyname('Scroll').asinteger;
  MUDAnsi.EventsOnFilter:=true;
  MUDAnsi.Autocopy:=Datawell.TableOptions.fieldbyname('Autocopy').asboolean;
  MUDAnsi.CopyToScrollback:=Datawell.TableOptions.fieldbyname('FeedScrollback').asboolean;
  PanelScrollTop.visible:=Datawell.TableOptions.fieldbyname('ScrollbackLabels').asboolean;
  PanelScrollBottom.visible:=Datawell.TableOptions.fieldbyname('ScrollbackLabels').asboolean;
  MenuMusicRepeat.checked:=Datawell.TableOptions3.fieldbyname('L31').asboolean;
  MenuMusicRandomize.checked:=Datawell.TableOptions3.fieldbyname('L60').asboolean;
  if MenuMusicRepeat.checked then MenuMusicRandomize.checked:=false;
  MenuShowToolbar.checked:=Datawell.TableOptions.fieldbyname('ToolbarShowing').asboolean;
  MenuShowStatusbar.checked:=Datawell.TableOptions.fieldbyname('HelpbarShowing').asboolean;
  MenuShowHPbar.checked:=Datawell.TableOptions.fieldbyname('ShowHP').asboolean;
  MenuShowHP2bar.checked:=Datawell.TableOptions.fieldbyname('ShowHP2').asboolean;
  MenuShowHP3bar.checked:=Datawell.TableOptions.fieldbyname('ShowHP3').asboolean;
  MenuShowHP4bar.checked:=Datawell.TableOptions.fieldbyname('ShowHP4').asboolean;
  PanelHP3Split.left:=Datawell.TableOptions.fieldbyname('HP3Offset').asinteger;
  PanelHP4Split.left:=Datawell.TableOptions.fieldbyname('HP4Offset').asinteger;
  GLine1.font.size:=Datawell.TableOptions.fieldbyname('HP3Size').asinteger;
  GLine1.selectall;
  GLine1.selattributes.size:=Datawell.TableOptions.fieldbyname('HP3Size').asinteger;
  GLine1.selstart:=0;
  GLine1.sellength:=0;
  GLine2.font.size:=Datawell.TableOptions.fieldbyname('HP3Size').asinteger;
  GLine2.selectall;
  GLine2.selattributes.size:=Datawell.TableOptions.fieldbyname('HP3Size').asinteger;
  GLine2.selstart:=0;
  GLine2.sellength:=0;
  LabelHP.font.size:=Datawell.TableOptions3.fieldbyname('I25').asinteger;
  LabelHPMax.font.size:=LabelHP.font.size;
  LabelSP.font.size:=LabelHP.font.size;
  LabelSPMax.font.size:=LabelHP.font.size;
  LabelGP1.font.size:=LabelHP.font.size;
  LabelGP1Max.font.size:=LabelHP.font.size;
  LabelGP2.font.size:=LabelHP.font.size;
  LabelGP2Max.font.size:=LabelHP.font.size;
  LabelSpecial.font.size:=Datawell.TableOptions.fieldbyname('HP4Size').asinteger;
  LabelSpecial2.font.size:=Datawell.TableOptions.fieldbyname('HP4Size').asinteger;
  LabelEName.font.size:=LabelHP.font.size;
  LabelEName2.font.size:=LabelHP.font.size;
//Initialize variables
  with Datawell.TableVariables do begin
    first;
    while not EOF do begin
      work:=fieldbyname('Initialize').asstring;
      if work <> '<do not initialize>' then begin
        edit;
        if work = '<clear on login>' then fieldbyname('FValue').asstring:=''
        else fieldbyname('FValue').asstring:=work;
        post;
      end;
      next;
    end;
  end;
  work:=Datawell.tableOptions.fieldbyname('Anchors').asstring;
  if copy(work,1,1) = '1' then MenuAnchor.checked:=true else MenuAnchor.checked:=false;
  if copy(work,2,1) = '1' then MenuAnchorTell.checked:=true else MenuAnchorTell.checked:=false;
  if copy(work,4,1) = '1' then MenuAnchorImagery.checked:=true else MenuAnchorImagery.checked:=false;
  if copy(work,5,1) = '1' then MenuAnchorFiltered.checked:=true else MenuAnchorFiltered.checked:=false;
  if copy(work,6,1) = '1' then MenuAnchorMap.checked:=true else MenuAnchorMap.checked:=false;
  if copy(work,9,1) = '1' then MenuAnchorCanvas.checked:=true else MenuAnchorCanvas.checked:=false;
  if Datawell.TableOptions.fieldbyname('ChatShowing').asboolean then LoadScreen(0);
  if Datawell.TableOptions.fieldbyname('TellShowing').asboolean then LoadScreen(1);
  if Datawell.TableOptions.fieldbyname('ImageryShowing').asboolean then LoadScreen(4);
  if Datawell.TableOptions.fieldbyname('FilteredShowing').asboolean then LoadScreen(6);
  if Datawell.TableOptions3.fieldbyname('L20').asboolean then LoadScreen(10);
  if Datawell.TableOptions3.fieldbyname('L57').asboolean then LoadScreen(2);
  ClearStatusFields;
  FormMap.dontdrawmap:=true;
  with FormMap do begin
    top:=2000;
    left:=2000;
    show;
    hide;
    top:=Datawell.TableOptions2.fieldbyname('MapTop').asinteger;
    left:=Datawell.TableOptions2.fieldbyname('MapLeft').asinteger;
    height:=Datawell.TableOptions3.fieldbyname('I3').asinteger;
    width:=Datawell.TableOptions3.fieldbyname('I4').asinteger;
    if Datawell.TableOptions2.fieldbyname('MapStayOnTop').asboolean then formstyle:=fsstayontop
    else formstyle:=fsnormal;
    MenuStayOnTop.checked:=Datawell.TableOptions2.fieldbyname('MapStayOnTop').asboolean;
    PopupStayOnTop.checked:=MenuStayOnTop.checked;
    visible:=Datawell.TableOptions2.fieldbyname('MapShowing').asboolean;
    MenuShowCartographer.checked:=visible;
    FormMap.MenuSpeedChart.checked:=Datawell.TableGlobals.fieldbyname('ChartSpeed').asboolean;
    FormMap.MenuTextChart.checked:=Datawell.TableGlobals.fieldbyname('ChartText').asboolean;
    FormMap.MenuFreeChart.checked:=Datawell.TableGlobals.fieldbyname('ChartFree').asboolean;
    FormMap.MenuCenterChart.checked:=Datawell.TableGlobals.fieldbyname('ChartCenter').asboolean;
  end;
  FormMap.dontdrawmap:=false;
  FormMap.DrawMap(true);
  LoadEditorOptions;
  MenuShowRecordTool.checked:=Datawell.TableOptions3.fieldbyname('L2').asboolean;
  EditSend.wordwrap:=Datawell.TableOptions2.fieldbyname('AutoExpand').asboolean;
  UpdateWindowCaptions;
  UpdateMenu;
  UpdateHPBars;
  UpdateBasebar;
  UpdateSendbar;
  UpdateToolbar;
  UpdateColors;
  UpdateTools;
  UpdateMasks;
  UpdateTickerLabel;
  UpdateHyperlinks;
  LoadSkin(1);
  LoadSkin(2);
  MUDAnsi.SelFGColor:=Datawell.FigureColor(Datawell.TableOptions.fieldbyname('FColorSelected').asinteger);
  MUDAnsi.SelBGColor:=Datawell.FigureColor(Datawell.TableOptions.fieldbyname('BColorSelected').asinteger);
  Scrollback.SelFGColor:=Datawell.FigureColor(Datawell.TableOptions.fieldbyname('FColorSelected').asinteger);
  Scrollback.SelBGColor:=Datawell.FigureColor(Datawell.TableOptions.fieldbyname('BColorSelected').asinteger);
  MUDAnsi.fullflash:=Datawell.TableOptions2.fieldbyname('FullFlash').asboolean;
  Scrollback.fullflash:=Datawell.TableOptions2.fieldbyname('FullFlash').asboolean;
  FormResize(nil);
  if MUDAnsi.selectedtext <> '' then MUDAnsi.unselect;
  if Scrollback.selectedtext <> '' then Scrollback.unselect;
  Datawell.lastplayer:=Datawell.player;
  Datawell.lastmud:=Datawell.mud;
  work:=Datawell.exedir+'\keyhistory.txt';
  if (Datawell.TableGlobals.fieldbyname('L3').asboolean) and (fileexists(work)) then begin
    History.clear;
    if FileExists(work) then
      History.loadfromfile(work);
    HistoryI:=History.count;
  end;
  EditSendChange(nil);
  PopulateRecord;
  UpdateLED;
end;

procedure TFormMain.SaveOptions(partial: boolean);
var
  work: string;
  KH: TextFile;
  i: integer;
begin
  Datawell.TableGlobals.edit;
  Datawell.TableGlobals.fieldbyname('ChartSpeed').asboolean:=FormMap.MenuSpeedChart.checked;
  Datawell.TableGlobals.fieldbyname('ChartText').asboolean:=FormMap.MenuTextChart.checked;
  Datawell.TableGlobals.fieldbyname('ChartFree').asboolean:=FormMap.MenuFreeChart.checked;
  Datawell.TableGlobals.fieldbyname('ChartCenter').asboolean:=FormMap.MenuCenterChart.checked;
  Datawell.TableGlobals.post;
  if panicclosing then begin
    Datawell.TableOptions.edit;
    if copy(panicwindows,2,1) = '1' then
      Datawell.TableOptions.fieldbyname('ChatShowing').asboolean:=true
    else Datawell.TableOptions.fieldbyname('ChatShowing').asboolean:=false;
    if copy(panicwindows,3,1) = '1' then
      Datawell.TableOptions.fieldbyname('TellShowing').asboolean:=true
    else Datawell.TableOptions.fieldbyname('TellShowing').asboolean:=false;
    if copy(panicwindows,4,1) = '1' then
      Datawell.TableOptions.fieldbyname('StatusShowing').asboolean:=true
    else Datawell.TableOptions.fieldbyname('StatusShowing').asboolean:=false;
    if copy(panicwindows,5,1) = '1' then
      Datawell.TableOptions.fieldbyname('ImageryShowing').asboolean:=true
    else Datawell.TableOptions.fieldbyname('ImageryShowing').asboolean:=false;
    if copy(panicwindows,6,1) = '1' then
      Datawell.TableOptions.fieldbyname('FilteredShowing').asboolean:=true
    else Datawell.TableOptions.fieldbyname('FilteredShowing').asboolean:=false;
    Datawell.TableOptions.post;
    Datawell.TableOptions2.edit;
    if copy(panicwindows,7,1) = '1' then
      Datawell.TableOptions2.fieldbyname('DataShowing').asboolean:=true
    else Datawell.TableOptions2.fieldbyname('DataShowing').asboolean:=false;
    if copy(panicwindows,9,1) = '1' then
      Datawell.TableOptions2.fieldbyname('MapShowing').asboolean:=true
    else Datawell.TableOptions2.fieldbyname('MapShowing').asboolean:=false;
    Datawell.TableOptions2.post;
    Datawell.TableOptions3.edit;
    if copy(panicwindows,8,1) = '1' then
      Datawell.TableOptions3.fieldbyname('L20').asboolean:=true
    else Datawell.TableOptions3.fieldbyname('L20').asboolean:=false;
    if copy(panicwindows,10,1) = '1' then
      Datawell.TableOptions3.fieldbyname('L4').asboolean:=true
    else Datawell.TableOptions3.fieldbyname('L4').asboolean:=false;
    if copy(panicwindows,11,1) = '1' then
      Datawell.TableOptions3.fieldbyname('L57').asboolean:=true
    else Datawell.TableOptions3.fieldbyname('L57').asboolean:=false;
    Datawell.TableOptions3.post;
  end
  else begin
    Datawell.TableOptions.edit;
    Datawell.TableOptions.fieldbyname('ChatShowing').asboolean:=screens[0];
    Datawell.TableOptions.fieldbyname('TellShowing').asboolean:=screens[1];
    Datawell.TableOptions.fieldbyname('ImageryShowing').asboolean:=screens[4];
    Datawell.TableOptions.fieldbyname('FilteredShowing').asboolean:=screens[6];
    Datawell.TableOptions.post;
    Datawell.TableOptions2.edit;
    Datawell.TableOptions2.fieldbyname('DataShowing').asboolean:=screens[9];
    Datawell.TableOptions2.post;
    Datawell.TableOptions3.edit;
    Datawell.TableOptions3.fieldbyname('L20').asboolean:=screens[10];
    Datawell.TableOptions3.fieldbyname('L57').asboolean:=screens[2];
    Datawell.TableOptions3.post;
  end;
  if not partial then begin
    UnloadScreen(0);
    UnloadScreen(1);
    UnloadScreen(2);
    UnloadScreen(4);
    UnloadScreen(6);
    UnloadScreen(9);
    UnloadScreen(10);
  end;
  if screens[11] then begin
    with screenEditor do begin
      Datawell.TableOptions.edit;
      Datawell.TableOptions.fieldbyname('EditorTop').asinteger:=top;
      Datawell.TableOptions.fieldbyname('EditorLeft').asinteger:=left;
      Datawell.TableOptions.fieldbyname('EditorHeight').asinteger:=height;
      Datawell.TableOptions.fieldbyname('EditorWidth').asinteger:=width;
      Datawell.TableOptions.fieldbyname('EditorFontName').asstring:=Editor1.font.name;
      if Editor1.font.style = [fsbold] then Datawell.TableOptions.fieldbyname('EditorFontStyle').asinteger:=1
      else if Editor1.font.style = [fsitalic] then Datawell.TableOptions.fieldbyname('EditorFontStyle').asinteger:=2
      else if Editor1.font.style = [fsbold, fsitalic] then Datawell.TableOptions.fieldbyname('EditorFontStyle').asinteger:=3
      else Datawell.TableOptions.fieldbyname('EditorFontStyle').asinteger:=0;
      Datawell.TableOptions.fieldbyname('EditorFontSize').asinteger:=Editor1.font.size;
      Datawell.TableOptions.fieldbyname('EditorFColor').asinteger:=Editor1.font.color;
      Datawell.TableOptions.fieldbyname('EditorBColor').asinteger:=Editor1.color;
      Datawell.TableOptions.fieldbyname('EditorWrap').asboolean:=MenuEnableWordWrap.checked;
      Datawell.TableOptions.fieldbyname('AutotypeSave').asboolean:=MenuSaveAlert.checked;
      Datawell.TableOptions.fieldbyname('EditorClear').asboolean:=MenuClearOnAutotype.checked;
      Datawell.TableOptions.fieldbyname('EditorAsk').asboolean:=MenuAskOnEmpty.checked;
      Datawell.TableOptions.fieldbyname('EditorShowWidthbar').asboolean:=MenuShowWidthBar.checked;
      Datawell.TableOptions.fieldbyname('EditorStayOnTop').asboolean:=MenuStayOnTop.checked;
      Datawell.TableOptions.post;
      Tabs.activepage:=Tab1;
    end;
  end;
  Datawell.TableOptions.edit;
  Datawell.TableOptions.fieldbyname('Top').asinteger:=top;
  Datawell.TableOptions.fieldbyname('FLeft').asinteger:=left;
  Datawell.TableOptions.fieldbyname('Height').asinteger:=height;
  Datawell.TableOptions.fieldbyname('Width').asinteger:=width;
  Datawell.TableOptions.fieldbyname('FontName').asstring:=MUDAnsi.font.name;
  if MUDAnsi.font.style = [fsbold] then Datawell.TableOptions.fieldbyname('FontStyle').asinteger:=1
  else if MUDAnsi.font.style = [fsitalic] then Datawell.TableOptions.fieldbyname('FontStyle').asinteger:=2
  else if MUDAnsi.font.style = [fsbold, fsitalic] then Datawell.TableOptions.fieldbyname('FontStyle').asinteger:=3
  else Datawell.TableOptions.fieldbyname('FontStyle').asinteger:=0;
  Datawell.TableOptions.fieldbyname('FontSize').asinteger:=MUDAnsi.font.size;
  Datawell.TableOptions.fieldbyname('ToolbarShowing').asboolean:=MenuShowToolbar.checked;
  Datawell.TableOptions.fieldbyname('HelpbarShowing').asboolean:=MenuShowStatusbar.checked;
  Datawell.TableOptions.fieldbyname('ShowHP').asboolean:=MenuShowHPbar.checked;
  Datawell.TableOptions.fieldbyname('ShowHP2').asboolean:=MenuShowHP2bar.checked;
  Datawell.TableOptions.fieldbyname('ShowHP3').asboolean:=MenuShowHP3bar.checked;
  Datawell.TableOptions.fieldbyname('ShowHP4').asboolean:=MenuShowHP4bar.checked;
  Datawell.TableOptions.fieldbyname('HP3Offset').asinteger:=PanelHP3Split.left;
  Datawell.TableOptions.fieldbyname('HP4Offset').asinteger:=PanelHP4Split.left;
  Datawell.TableOptions.fieldbyname('HP3Size').asinteger:=GLine1.font.size;
  Datawell.TableOptions.fieldbyname('HP4Size').asinteger:=LabelSpecial.font.size;
  work:='';
  if MenuAnchor.checked then work:=work+'1' else work:=work+'0';
  if MenuAnchorTell.checked then work:=work+'1' else work:=work+'0';
  if MenuAnchorImagery.checked then work:=work+'1' else work:=work+'0';
  if MenuAnchorFiltered.checked then work:=work+'1' else work:=work+'0';
  if MenuAnchorMap.checked then work:=work+'1' else work:=work+'0';
  work:=work+'0';  //For defunct screen
  if MenuAnchorCanvas.checked then work:=work+'1' else work:=work+'0';
  Datawell.TableOptions.fieldbyname('Anchors').asstring:=work;
  Datawell.TableOptions.post;
  Datawell.TableOptions2.edit;
  with FormMap do begin
    Datawell.TableOptions2.fieldbyname('MapShowing').asboolean:=visible;
    if (panicclosing) and (copy(panicwindows,10,1) = '1') then
      Datawell.TableOptions2.fieldbyname('MapShowing').asboolean:=true;
    Datawell.TableOptions2.fieldbyname('MapTop').asinteger:=top;
    Datawell.TableOptions2.fieldbyname('MapLeft').asinteger:=left;
    Datawell.TableOptions2.fieldbyname('MapStayOnTop').asboolean:=MenuStayOnTop.checked;
  end;
  Datawell.TableOptions2.fieldbyname('FullFlash').asboolean:=MUDAnsi.fullflash;
  Datawell.TableOptions2.post;
  Datawell.TableOptions3.edit;
  Datawell.TableOptions3.fieldbyname('L41').asboolean:=(windowstate = wsmaximized);
  Datawell.TableOptions3.fieldbyname('L31').asboolean:=MenuMusicRepeat.checked;
  if MenuMusicRepeat.checked then MenuMusicRandomize.checked:=false;
  Datawell.TableOptions3.fieldbyname('L60').asboolean:=MenuMusicRandomize.checked;
  with FormMap do begin
    Datawell.TableOptions3.fieldbyname('I3').asinteger:=height;
    Datawell.TableOptions3.fieldbyname('I4').asinteger:=width;
  end;
  Datawell.TableOptions3.fieldbyname('L2').asboolean:=MenuShowRecordTool.checked;
  Datawell.TableOptions3.fieldbyname('I25').asinteger:=LabelHP.font.size;
  Datawell.TableOptions3.fieldbyname('I29').asinteger:=MUDAnsi.linewrap;
  Datawell.TableOptions3.post;
  if not partial then begin
    if Datawell.TableGlobals.fieldbyname('L3').asboolean then begin
      //Save keyhistory to file
      AssignFile(KH,Datawell.exedir+'\keyhistory.txt');
      Rewrite(KH);
      for i:=0 to History.count-1 do WriteLn(KH,History[i]);
      CloseFile(KH);
    end;
  end;
end;

procedure TFormMain.TimerRecordPulseTimer(Sender: TObject);
begin
  MacroPulse1.bringtofront;
  TimerRecordPulse.enabled:=false;
end;

function TFormMain.ParseAutotype(data: string): boolean;
var
  which: integer;
  empty: boolean;
begin
  result:=false;
  if copy(data,1,1) <> 'u' then exit;
  if DoDelaying(data) then exit;
  delete(data,1,1);
  which:=0;
  if data = '' then which:=999
  else if copy(data,1,2) = ' 1' then which:=1
  else if copy(data,1,2) = ' 2' then which:=2
  else if copy(data,1,2) = ' 3' then which:=3
  else if copy(data,1,2) = ' 4' then which:=4;
  if which = 0 then exit;
  result:=true;
  if which > 1 then begin
    if not Datawell.CheckRinged(false,'multiple Autotyper files') then exit;
  end;
  if not screens[11] then begin
    systemtext('There are no files open in the Autotyper',0);
    exit;
  end;
  empty:=false;
  case which of
    1: if screenEditor.Editor1.lines.count < 1 then empty:=true;
    2: if screenEditor.Editor2.lines.count < 1 then empty:=true;
    3: if screenEditor.Editor3.lines.count < 1 then empty:=true;
    4: if screenEditor.Editor4.lines.count < 1 then empty:=true;
  999: if screenEditor.ActiveEditor.lines.count < 1 then empty:=true;
  end;
  if empty then begin
    if which = 999 then systemtext('The active Autotyper file is empty',0)
    else systemtext('Autotyper file '+inttostr(which)+' is empty',0);
    exit;
  end;
  screenEditor.FocusFile(which);
  screenEditor.MenuAutotypeClick(nil);
end;

function TFormMain.ParseActions(data: string; kind: integer): boolean;
var
  commands, amts: TStringList;
  element, work, work2, originaldata, qamt: string;
  i, j, p, q: integer;
  reversing, freversing: boolean;
begin
  result:=true;
  data:=Datawell.CutTrailingSpaces(data);
  qamt:='1';
  reversing:=false;
  freversing:=false;
  originaldata:=data;
  if copy(data,1,1) = '-' then begin
    reversing:=true;
    delete(data,1,1);
  end;
  if copy(data,1,1) = '-' then begin
    freversing:=true;
    delete(data,1,1);
  end;
  if data = '' then begin
    data:=lastq;
    originaldata:=lastq;
  end;
  while copy(data,1,1) = ' ' do delete(data,1,1);
  i:=pos(' ',data);
  q:=pos(Datawell.TableOptions.fieldbyname('Quickchar').asstring,data);
  if (i > 0) and (q < 1) then begin
    result:=ProcessMulti(data,i,kind);
    exit;
  end;
  commands:=TStringList.create;
  amts:=TStringList.create;
  lastq:=data;
  while length(data) > 0 do begin
    element:=copy(data,1,1); delete(data,1,1);
    work:='';
    if element = Datawell.TableOptions.fieldbyname('Quickchar').asstring then begin
      p:=pos(Datawell.TableOptions.fieldbyname('Quickchar').asstring,data);
      if p > 0 then begin
        work:=copy(data,1,p-1);
        delete(data,1,p);
        commands.add('XwXX'+work);
        amts.add(qamt);
        qamt:='1';
        continue;
      end
      else begin
        work:=data;
        commands.add('XwXX'+work);
        amts.add(qamt);
        qamt:='1';
        break;
      end;
    end;
    element:=lowercase(element);
    if (length(data) < 1) and (ord(element[1]) >= 48) and
       (ord(element[1]) <= 57) then work:=work+element;
    while (ord(element[1]) >= 48) and (ord(element[1]) <= 57) and (length(data) > 0) do begin
      work:=work+element;
      element:=copy(data,1,1); delete(data,1,1);
      if (length(data) < 1) and (ord(element[1]) >= 48) and
         (ord(element[1]) <= 57) then work:=work+element;
    end;
    if element = Datawell.TableOptions.fieldbyname('Quickchar').asstring then begin
      data:=Datawell.TableOptions.fieldbyname('Quickchar').asstring+data;
      qamt:=work;
      continue;
    end;
    if (ord(element[1]) >= 97) and (ord(element[1]) <= 122) then begin
      commands.add(element);
      if work <> '' then begin
        work:=copy(work,1,5);
        if strtoint(work) > 99 then work:='99';
        amts.add(work);
      end
      else amts.add('1');
    end;
  end;
  if kind = 1 then kind:=7;
  if FigureEcho(kind) then begin
    if reversing then begin
      if freversing then
        MUDAnsi.InsertFormatedText(FigureFColor(kind),FigureBColor(kind),
          'Q: '+originaldata+' (full reversed)'+#10,false,false)
      else MUDAnsi.InsertFormatedText(FigureFColor(kind),FigureBColor(kind),
        'Q: '+originaldata+' (reversed)'+#10,false,false);
    end
    else MUDAnsi.InsertFormatedText(FigureFColor(kind),FigureBColor(kind),
      'Q: '+originaldata+#10,false,false);
  end;
  if reversing then begin
    for i:=commands.count-1 downto 0 do begin
      for j:=1 to strtoint(amts[i]) do begin
        if copy(commands[i],1,4) = 'XwXX' then begin
          work2:=copy(commands[i],5,9999);
          if work2 <> '' then begin
            if not freversing then work2:=Datawell.Reverse(work2);
            if work2 <> '' then ParseMain(work2,kind);
          end;
          result:=true;
        end
        else begin
          work2:=Datawell.FigureQuickchar(commands[i]);
          if work2 <> '' then begin
            if not freversing then work2:=Datawell.Reverse(work2);
            if work2 <> '' then ParseMain(work2,kind);
            result:=true;
          end;
        end;
      end;
    end;
  end
  else begin
    for i:=0 to commands.count-1 do begin
      for j:=1 to strtoint(amts[i]) do begin
        if copy(commands[i],1,4) = 'XwXX' then begin
          work2:=copy(commands[i],5,9999);
          ParseMain(work2,kind);
          result:=true;
        end
        else begin
          work2:=Datawell.FigureQuickchar(commands[i]);
          if work2 <> '' then begin
            ParseMain(work2,kind);
            result:=true;
          end;
        end;
      end;
    end;
  end;
  commands.free;
  amts.free;
end;

function TFormMain.ProcessMulti(const data: string; i: integer; kind: integer): boolean;
var
  work, work2: string;
  amt: integer;
begin
  result:=false;
  work:='';
  work2:=copy(data,i+1,9999);
  amt:=Datawell.tointpure(copy(data,1,i-1));
  if amt < 1 then exit;
  result:=true;
  if amt > 99 then amt:=99;
  if Datawell.TableOptions.fieldbyname('Typed').asboolean then begin
    MUDAnsi.InsertFormatedText(FigureFColor(kind),FigureBColor(kind),
      'Repeat '+inttostr(amt)+': '+work2+#10,false,false);
  end;
  for i:=1 to amt do
    ParseMain(work2,kind);
end;

procedure TFormMain.MenuAboutClick(Sender: TObject);
var
  form: TFormAbout;
begin
  form:=TFormAbout.create(self);
  with form.ImageLogo.canvas do begin
    brush.color:=clbtnface;
    BrushCopy(Bounds(0,0,112,50),ImageGA.picture.bitmap,
      Bounds(0,0,112,50),clsilver);
  end;
  form.showmodal;
  form.free;
end;

procedure TFormMain.MenuExitClick(Sender: TObject);
begin
  close;
end;

procedure TFormMain.MenuOpenAutotyperClick(Sender: TObject);
begin
  if (tabbing) and (not screens[11]) then exit;
  LoadScreen(11);
  screenEditor.windowstate:=wsnormal;
  screenEditor.bringtofront;
  screenEditor.ActiveEditor.setfocus;
  if tabbing then begin
    tabbing:=false;
    abort;
  end;
end;

procedure TFormMain.MenuPanicClick(Sender: TObject);
var
  form: TFormClock;
  oldtitle: string;
  showings: array [0..15] of boolean;
  doingmusic, s_editor, s_map: boolean;
begin
  doingmusic:=(MP.mode = mpplaying);
  MenuMusicPause.click;
  showings[0]:=screens[0]; //chat
  showings[1]:=screens[1]; //tell
  showings[2]:=screens[2]; //room
  showings[4]:=screens[4]; //imagery
  showings[6]:=screens[6]; //filtered
  showings[10]:=screens[10]; //canvas
  UnloadScreen(0);
  UnloadScreen(1);
  UnloadScreen(2);
  UnloadScreen(4);
  UnloadScreen(6);
  UnloadScreen(10);
  s_editor:=screens[11];
  if screens[11] then screenEditor.hide;
  s_map:=FormMap.visible;
  panicwindows:='';
  if s_editor then panicwindows:=panicwindows+'1' else panicwindows:=panicwindows+'0';
  if showings[0] then panicwindows:=panicwindows+'1' else panicwindows:=panicwindows+'0';
  if showings[1] then panicwindows:=panicwindows+'1' else panicwindows:=panicwindows+'0';
  if showings[2] then panicwindows:=panicwindows+'1' else panicwindows:=panicwindows+'0';
  if showings[4] then panicwindows:=panicwindows+'1' else panicwindows:=panicwindows+'0';
  if showings[6] then panicwindows:=panicwindows+'1' else panicwindows:=panicwindows+'0';
  if showings[10] then panicwindows:=panicwindows+'1' else panicwindows:=panicwindows+'0';
  if s_map then panicwindows:=panicwindows+'1' else panicwindows:=panicwindows+'0';
  panicwindows:=panicwindows+'0'; //For defunct screen
  oldtitle:=application.title;
  DoMacro(Datawell.TableOptions.fieldbyname('PanicMacro').asstring,0,false);
  FormMap.hide;
  hide;
  form:=TFormClock.create(self);
  form.top:=0;
  form.left:=0;
  application.title:='PClock';
  application.icon:=IconClock.picture.icon;
  haltsounds:=true;
  application.showhint:=false;
  clockshowing:=true;
  panicking:=true;
  form.showmodal;
  panicking:=false;
  Datawell.idle:=0;
  form.free;
  DoMacro(Datawell.TableOptions2.fieldbyname('PanicMacro2').asstring,0,false);
  if panicclosing then begin
    close;
    exit;
  end;
  clockshowing:=false;
  application.showhint:=true;
  haltsounds:=false;
  application.icon:=IconMain.picture.icon;
  application.title:=oldtitle;
  if showings[0] then LoadScreen(0);
  if showings[1] then LoadScreen(1);
  if showings[2] then LoadScreen(2);
  if showings[4] then LoadScreen(4);
  if showings[6] then LoadScreen(6);
  if showings[10] then LoadScreen(10);
  panicking:=true;
  if (s_editor) and (screens[11]) then screenEditor.show;
  panicking:=false;
  FormMap.visible:=s_map;
  if doingmusic then MP.play;
  if Datawell.TableOptions3.fieldbyname('L3').asboolean then MenuLock.click
  else begin
    show;
    if delayeddisconnect then ShowDisconnect;
  end;
end;

procedure TFormMain.MenuLockClick(Sender: TObject);
var
  form: TFormSecure;
  oldtitle: string;
  showings: array [0..11] of boolean;
  doingmusic, s_editor, s_map: boolean;
begin
  form:=TFormSecure.create(self);
  form.LabelChar.caption:=Datawell.player+' is locked';
  form.password:=Datawell.password;
  doingmusic:=(MP.mode = mpplaying);
  MenuMusicPause.click;
  showings[0]:=screens[0];
  showings[1]:=screens[1];
  showings[2]:=screens[2];
  showings[4]:=screens[4];
  showings[6]:=screens[6];
  showings[10]:=screens[10];
  UnloadScreen(0);
  UnloadScreen(1);
  UnloadScreen(2);
  UnloadScreen(4);
  UnloadScreen(6);
  UnloadScreen(10);
  s_editor:=screens[11];
  if screens[11] then screenEditor.hide;
  s_map:=FormMap.visible;
  FormMap.hide;
  hide;
  oldtitle:=application.title;
  application.title:='PLock';
  application.icon:=IconLock.picture.icon;
  PlaySound('lock',1,1,0,false);
  haltsounds:=true;
  if Datawell.password = '' then begin
    form.EditPassword.hide;
    form.BtnOK.enabled:=true;
    form.LabelPassword.hide;
  end;
  application.showhint:=false;
  lockshowing:=true;
  form.showmodal;
  form.free;
  lockshowing:=false;
  application.showhint:=true;
  haltsounds:=false;
  PlaySound('lock',1,1,0,false);
  application.icon:=IconMain.picture.icon;
  application.title:=oldtitle;
  if showings[0] then LoadScreen(0);
  if showings[1] then LoadScreen(1);
  if showings[2] then LoadScreen(2);
  if showings[4] then LoadScreen(4);
  if showings[6] then LoadScreen(6);
  if showings[10] then LoadScreen(10);
  panicking:=true;
  if (s_editor) and (screens[11]) then screenEditor.show;
  panicking:=false;
  FormMap.visible:=s_map;
  show;
  if doingmusic then MP.play;
  if delayeddisconnect then ShowDisconnect;
end;

function TFormMain.ProcessAlias(var data: string; kind: integer; over: boolean): boolean;
var
  i: integer;
  original, work: string;
  reversing, freversing: boolean;
begin
  result:=false;
  reversing:=false;
  freversing:=false;
  original:=data;
  i:=pos(' ',data);
  if i < 1 then begin
    work:=data;
    data:='';
  end
  else begin
    work:=copy(data,1,i-1);
    delete(data,1,i);
  end;
  if copy(work,1,1) = '-' then begin
    delete(work,1,1);
    reversing:=true;
  if copy(work,1,1) = '-' then begin
      delete(work,1,1);
      freversing:=true;
    end;
  end;
  if not DoAlias(work,data,kind,reversing,freversing,over) then begin
    data:=original;
    exit;
  end;
  result:=true;
  if not Datawell.TableOptions2.fieldbyname('DisableAliasLED').asboolean then begin
    PanelLED.color:=cllime;
    TimerLED.enabled:=false;
    TimerLED.interval:=750;
    TimerLED.enabled:=true;
  end;
end;

procedure TFormMain.TimerLEDTimer(Sender: TObject);
begin
  with PanelLED do begin
    if color = cllime then begin
      TimerLED.interval:=500;
      color:=clgreen;
    end
    else if color = clred then begin
      TimerLED.interval:=500;
      color:=clmaroon;
    end
    else if color = claqua then begin
      TimerLED.interval:=500;
      color:=clteal;
    end
    else if color = clblue then begin
      TimerLED.interval:=500;
      color:=clnavy;
    end
    else if color = clyellow then begin
      TimerLED.interval:=500;
      color:=clolive;
    end
    else if color = clwhite then begin
      TimerLED.interval:=500;
      color:=clsilver;
    end
    else if color = clfuchsia then begin
      TimerLED.interval:=500;
      color:=clpurple;
    end
    else begin
      TimerLED.enabled:=false;
      UpdateLED;
    end;
  end;
end;

function TFormMain.DoMacro(mac: string; kind: integer; over: boolean): boolean;
var
  script: string;
begin
  result:=false;
  if mac = '' then exit;
  if recording then exit;
  if datawell.TableMacros.Locate('MACRO', mac, []) then
  begin
    script := datawell.TableMacros.fieldbyname('Script').AsString;
    result:=script <> '';
  end;
  if not result then
    exit;
  if (not over) or (kind = 1) then kind:=4;
  Scripts.CurrentContext := kind;
  Scripts.RunScript(script);
end;

procedure TFormMain.ExecuteAliasLine(count: integer; work, wild: string; kind: integer);
begin
   if (count = 1) and (pos('$',work) < 1) then work:=work+' $';
   work:=Wildcard(work,wild,0);
   ParseMain(work,kind);
end;

procedure TFormMain.ExecuteAlias(const data, wild: string; kind: integer; rev, frev: boolean);
var
   work: string;
   coms: TStringList;
   i: integer;
begin
   coms := TStringList.Create;
   try
      coms.Text := data;
      if rev then begin
         if frev then begin
           //Full reversed alias
           for i:=coms.count-1 downto 0 do
              ExecuteAliasLine(coms.Count, coms[i], wild, kind);
         end
         else begin
            //Reversed alias
            for i:=coms.count-1 downto 0 do begin
               work:=Datawell.Reverse(coms[i]);
               if work = '' then continue;
               ExecuteAliasLine(coms.Count, work, wild, kind);
            end;
         end;
      end
      else begin
         //Forward (normal) alias
         for i:=0 to coms.count-1 do
            ExecuteAliasLine(coms.Count, coms[i], wild, kind);
      end;
   finally
      coms.Free;
   end;
end;

function TFormMain.DoAlias(ali, wild: string; kind: integer; rev, frev, over: boolean): boolean;
var
   work: string;
begin
   result:=false;
   if ali = '' then exit;
   if recording then exit;
   ali:=Datawell.subs('"','',ali);
   if (not over) or (kind = 1) then
      kind:=3;
   //Locate alias
   if datawell.TableAliases.Locate('MASTER;ALIAS', VarArrayOf([Datawell.masterinteger, ali]), []) then
   begin
      work := datawell.TableAliases.fieldbyname('Script').AsString;
      if work = '' then
         Exit;
      scripts.CurrentContext := kind;
      if StartsText('LegacyAlias(#''', work) and EndsStr(');', work) then
      begin
         insert(', ' + QuotedStr(wild), work, length(work) - 1);
         if rev then
         begin
            if frev then
               insert(', aoFullReverse', work, length(work) - 1)
            else insert(', aoReverse', work, length(work) - 1)
         end;
      end
      else work := format('var params: string = %s;'#13#10, [QuotedStr(wild)]) + work;
      scripts.RunScript(work);
      result := true;
   end;
end;

procedure TFormMain.TimerRecordTimer(Sender: TObject);
begin
  if not recording then begin
    TimerRecord.enabled:=false;
    exit;
  end;
  if MacroRecord.visible then begin
    MacroRecord.hide;
    MacroStop.show;
    TimerRecord.interval:=1000;
  end
  else begin
    MacroStop.hide;
    MacroRecord.show;
    TimerRecord.interval:=500;
  end;
end;

procedure TFormMain.BtnMacClick(Sender: TObject);
begin
  case (sender as TSpeedButton).tag of
    1: begin
         EditAlias.hide;
         EditMacro.show;
       end;
    2: begin
         EditMacro.hide;
         EditAlias.show;
       end;
  end;
  PopulateRecord;
end;

procedure TFormMain.MenuAutotypeClick(Sender: TObject);
begin
  if not screens[11] then exit;
  screenEditor.MenuAutotypeClick(sender);
end;

procedure TFormMain.MenuMapperClick(Sender: TObject);
var form: TFormMapper;
begin
  if not Datawell.CheckRinged2('graph paper generator') then exit;
  form:=TFormMapper.create(self);
  form.showmodal;
  form.free;
end;

procedure TFormMain.TelnetDataAvailable(Sender: TTnCnx; Buffer: Pointer;
  Len: Integer);
var
  mess, scol: string;
  bufStr: PAnsiChar absolute Buffer;
begin
  mess:=string(strpas(bufStr));
  mess:=Datawell.FilterProfanity(mess);
  if sender.tag = 1 then begin
    if Datawell.TableOptions3.fieldbyname('L46').asboolean then exit;
  end
  else begin
    if Datawell.TableOptions3.fieldbyname('L47').asboolean then exit;
    scol:='';
    if Datawell.TableOptions3.fieldbyname('L50').asboolean then begin
      scol:=Datawell.TableOptions3.fieldbyname('S2').asstring;
      if Datawell.TableOptions3.fieldbyname('L49').asboolean then scol:=scol+';3';
    end
    else if Datawell.TableOptions3.fieldbyname('L49').asboolean then scol:='[3';
    if scol <> '' then scol:=chr(27)+scol+'m';
//Assimilate the resets
    mess:=Datawell.subs(chr(27)+'[0m',Datawell.specialcode,mess);
    mess:=Datawell.subs(chr(27)+'[m',Datawell.specialcode,mess);
//Have all the resets start off again with the colored code
    mess:=Datawell.subs(Datawell.specialcode,chr(27)+'[0m'+scol,mess);
//Wrap ansi around the packet
    mess:=scol+Datawell.TableOptions3.fieldbyname('S1').asstring+mess+chr(27)+'[0m';
  end;
  sender.pause;
  try
    MUDAnsi.process(mess);
  finally
    UpdateTotalLabel;
    sender.resume;
  end;
end;

procedure TFormMain.PanelSeparatorMouseMove(Sender: TObject;
  Shift: TShiftState; X, Y: Integer);
var newheight: integer;
begin
  if not mouseisdown then begin
    LabelStatus.caption:='';
    exit;
  end;
  newheight:=PanelScroll.height+y;
  if newheight < scrollmin then newheight:=scrollmin;
  if newheight > PanelLeftBar.height-barbuffer-PanelSend.height
    then newheight:=PanelLeftBar.height-barbuffer-PanelSend.height;
  PanelScroll.height:=newheight;
  LEDScrollback.height:=newheight;
  UpdateScrollbackLabels;
end;

procedure TFormMain.PanelSeparatorMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  mouseisdown:=true;
end;

procedure TFormMain.PanelSeparatorMouseUp(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  mouseisdown:=false;
end;

procedure TFormMain.MenuEscapeClick(Sender: TObject);
var
  doexit: boolean;
begin
  if visible then EditSend.setfocus;
  FormMap.AbortChart;
  if (Datawell.repeatstring <> '') and (PanelScroll.height = 0) then begin
    Datawell.repeatstring:='';
    TimerRepeat.enabled:=false;
    SystemText('Repeating stopped',0);
  end;
  if PanelSends.visible then PanelSends.hide;
  FormResize(nil);
  if MUDAnsi.selectedtext <> '' then MUDAnsi.unselect;
  if Scrollback.selectedtext <> '' then Scrollback.unselect;
  doexit:=not Datawell.TableOptions.fieldbyname('FEscape').asboolean;
  if ListHistory.visible then begin
    CloseHistory;
    if doexit then exit;
  end;
  if EditHistory.visible then begin
    ClearHistoryVars;
    if doexit then exit;
  end;
  if PanelScroll.height > 0 then begin
    Datawell.TableOptions.edit;
    Datawell.TableOptions.fieldbyname('ScrollPosition').asinteger:=PanelScroll.height;
    Datawell.TableOptions.post;
    PanelScroll.height:=0;
    LEDScrollback.height:=0;
    if doexit then exit;
  end;
  if Datawell.TableOptions.fieldbyname('ClearSending').asboolean then begin
    if (LabelDelay.visible) or (Sends.count > 0) then begin
      ClearSending;
      if doexit then exit;
    end;
  end;
  if EditSend.text <> '' then begin
    bypass:=true;
    EditSend.text:='';
    bypass:=false;
    if doexit then exit;
  end;
end;

procedure TFormMain.MenuDoScrollbackClick(Sender: TObject);
begin
  if PanelScroll.height > 0 then begin
    ScrollUp(-1);
    exit;
  end;
  Scrollback.display:=nil;
  Scrollback.display:=MUDAnsi;
  Scrollback.scrollto(Scrollback.flines.count);
  if Datawell.TableOptions.fieldbyname('ScrollPosition').asinteger-barbuffer >=
    PanelLeftBar.height-barbuffer-PanelSend.height then begin
    Datawell.TableOptions.edit;
    Datawell.TableOptions.fieldbyname('ScrollPosition').asinteger:=
      PanelLeftBar.height-barbuffer-PanelSend.height;
    Datawell.TableOptions.post;
  end;
  PanelScroll.height:=Datawell.TableOptions.fieldbyname('ScrollPosition').asinteger;
  LEDScrollback.height:=PanelScroll.height;
  if Datawell.TableOptions.fieldbyname('Pageup').asboolean then ScrollUp(-1);
  UpdateScrollbackLabels;
end;

procedure TFormMain.FormMouseWheelUp(Sender: TObject; Shift: TShiftState;
  MousePos: TPoint; var Handled: Boolean);
begin
  if PanelScroll.height > 0 then ScrollUp(3)
  else MenuDoScrollbackClick(Sender);
end;

procedure TFormMain.FormMouseWheelDown(Sender: TObject; Shift: TShiftState;
  MousePos: TPoint; var Handled: Boolean);
begin
  ScrollDown(3);
end;

procedure TFormMain.ScrollUp(amt: integer);
begin
  if Scrollback.curscrollpos < 1 then exit;
  if amt < 0 then
    Scrollback.scrollto(Scrollback.curscrollpos-Scrollback.FClientSize.y)
  else Scrollback.scrolldown(amt);
  Scrollback.refresh;
  UpdateScrollbackLabels;
end;

procedure TFormMain.ScrollDown(amt: integer);
begin
  if Datawell.TableOptions3.fieldbyname('L44').asboolean then begin
    if LabelBottom.caption = LabelSTotal.caption then begin
      BtnCloseScrollBack.click;
      exit;
    end;
  end;
  if amt < 0 then
    Scrollback.scrollto(Scrollback.curscrollpos+Scrollback.FClientSize.y)
  else Scrollback.scrollup(amt);
  Scrollback.refresh;
  UpdateScrollbackLabels;
end;

procedure TFormMain.MenuScrollforwardClick(Sender: TObject);
begin
  if PanelScroll.height > 0 then ScrollDown(-1);
end;

procedure TFormMain.TimerTimeTimer(Sender: TObject);
var
  newcap: string;
  i, j: integer;
  F: TextFile;
begin
//********************************************
//The below items happen once every 1/2 second
//********************************************
  Mudansi.flash;
  Scrollback.flash;
  MP.hint:='';
  //Do animation
  DoAnimation;
  CheckTicker;
  if timeflip then begin
    timeflip:=false;
    exit;
  end;
  timeflip:=true;
//**************************************
//The below items happen once per second
//**************************************
  //Update connected information in the caption
  if Datawell.connected then begin
    inc(onlinetime);
    if not ((onlinetime mod 60) > 0) and (pos('(',caption) > 1) then UpdateCaption;
  end;
  //Reset the events limiter
  inc(tickerevents);
  if tickerevents >= 5 then begin
    tickerevents:=0;
    eventsdone:=0;
    commandsdone:=0;
    PanelLeftBar.color:=clgray;
  end;
  //Check the Ticker items
  //Update the new time label
  newcap:=formatdatetime('h:mm am/pm',now);
  if newcap = LabelTime.caption then exit;
//**************************************
//The below items happen once per minute
//**************************************
  //Update the new time label
  LabelTime.caption:=newcap;
  CheckIdlePanic;
  //Increment the connected time and total time
  i:=Datawell.TableGlobals.fieldbyname('Last').asinteger;
  j:=Datawell.TableGlobals.fieldbyname('I1').asinteger;
  if j < 0 then j:=0;
  Datawell.TableGlobals.edit;
  Datawell.TableGlobals.fieldbyname('Last').asinteger:=i+1;
  Datawell.TableGlobals.fieldbyname('I1').asinteger:=j+1;
  Datawell.TableGlobals.post;
//**************************************
//The below items happen once per 10 minutes
//**************************************
  if Datawell.TableGlobals.fieldbyname('I1').asinteger mod 10 <> 0 then exit;
  if MenuLogToFile.checked then begin
    AssignFile(F,DialogSave.filename);
    Append(F);
    WriteLn(F,'['+timetostr(time)+'  '+datetostr(date)+']');
    CloseFile(F);
  end;
end;

procedure TFormMain.SyncTickers;
var
   ticker: TPortalTimestamp;
   found: boolean;
   id, tick: TField;
begin
   datawell.TableTicker.First;
   id := datawell.TableTicker.FieldByName('ID');
   tick := datawell.TableTicker.FieldByName('TICK');
   while not datawell.TableTicker.Eof do
   begin
      found := false;
      for ticker in FTickers do
         if ticker.TickerID = ID.AsInteger then
         begin
            found := true;
            break;
         end;
      if not found then
         FTickers.Add(TPortalTimestamp.Create(tick.AsInteger * 1000, id.AsInteger));
      datawell.TableTicker.Next;
   end;
end;

procedure TFormMain.CheckTicker;
var
   table: TCustomClientDataset;
   ticker: TPortalTimestamp;
   i, ID: integer;
   actions: TStringList;
   action: string;
begin
   if not Datawell.tablessetup then exit;
   if not Datawell.TableOptions.fieldbyname('EnableTicker').asboolean then exit;
   if ImageEnableEvent.visible then exit;
   actions := nil;
   try
     table := Datawell.TableTicker;
     if FTickers.Count <> table.RecordCount then
        SyncTickers;
     for i := FTickers.Count - 1 downto 0 do
     begin
        ticker := FTickers[i];
        if ticker.timeRemaining = 0 then
        begin
           id := ticker.TickerID;
           FTickers.Delete(i);
           assert(table.Locate('ID', id, []));
           FTickers.Add(TPortalTimestamp.Create(table['TICK'] * 1000, id));
           if actions = nil then
              actions := TStringList.Create;
           actions.add(table['ACTION']);
        end;
     end;
     if assigned(actions) then
     begin
        Scripts.CurrentContext := 9;
        for action in actions do
           Scripts.RunScript(action);
     end;
   finally
      actions.Free;
   end;
end;

procedure TFormMain.TelnetSessionConnected(Sender: TTnCnx; Error: Word);
var alreadyconnected: boolean;
begin
  alreadyconnected:=Datawell.connected;
  UpdateConnection(TTnCnx(sender).tag,true);
  if not alreadyconnected then begin
    if Sends.count > 0 then begin
      Sends.insert(0,'      wait 1');
      DoSend;
    end;
  end;
end;

procedure TFormMain.TelnetSessionClosed(Sender: TTnCnx; Error: Word);
begin
  UpdateConnection(TTnCnx(sender).tag,false);
  if TTnCnx(sender).tag > 1 then exit;
  ClearSending;
  LogSession;
  onlinetime:=0;
  if recording then BtnRecord.click;
  FormMap.BtnChart.down:=false;
  FormMap.BtnFollow.down:=false;
  FormMap.UpdateCharting(0,true);
  MenuLogToFile.checked:=false;
  UpdateLogger;
  SystemText(#10+'<<Session Disconnected: '+formatdatetime('h:mm am/pm',now)+'>>',0);
  if not online then exit;
  online:=false;
  if overrideclose then exit;
  if (clockshowing) or (lockshowing) then begin
    delayeddisconnect:=true;
    exit;
  end;
  if Datawell.connected2 then ChangeControl(2);
  ShowDisconnect;
end;

procedure TFormMain.ShowDisconnect;
var
  form: TFormDisconnect;
  closing: integer;
begin
  delayeddisconnect:=false;
  closing:=1;
  if not Datawell.TableGlobals.FieldByName('L11').asboolean then begin
    form:=TFormDisconnect.create(self);
    showingdisconnect:=true;
    form.showmodal;
    showingdisconnect:=false;
    closing:=form.closing;
    form.free;
  end;
  Datawell.idle:=0;
  Datawell.disconnected:=true;
  case closing of
    1: MenuReconnect.click;
    2: MenuExit.click;
    3: Datawell.workingoffline:=true;
  end;
end;

procedure TFormMain.MenuScrollWAYBackClick(Sender: TObject);
begin
  if TMenuItem(sender).tag = 1 then begin
    if EditSend.lines.count > 1 then begin
      EditSend.selstart:=0;
      EditSend.sellength:=0;
    end;
    exit;
  end;
  Scrollback.Scrollto(0);
  UpdateScrollbackLabels;
end;

procedure TFormMain.MenuScrollWAYDownClick(Sender: TObject);
begin
  if TMenuItem(sender).tag = 1 then begin
    if EditSend.lines.count > 1 then begin
      EditSend.selstart:=99999;
      EditSend.sellength:=0;
    end;
    exit;
  end;
  Scrollback.Scrollto(999999);
  UpdateScrollbackLabels;
end;

procedure TFormMain.MenuCopyClick(Sender: TObject);
var str: string;
begin
  str:=EditSend.seltext;
  if str = '' then begin
    if PanelScroll.height > 0 then str:=Scrollback.selectedtext;
  end;
  if str = '' then str:=MUDAnsi.selectedtext;
  if str = '' then exit;
  MemoCopy.text:=str;
  MemoCopy.selectall;
  MemoCopy.CopyToClipboard;
end;

procedure TFormMain.MenuCopyToAutotyperClick(Sender: TObject);
var str: string;
begin
  str:=EditSend.seltext;
  if str = '' then begin
    if PanelScroll.height > 0 then str:=Scrollback.selectedtext;
  end;
  if str = '' then str:=MUDAnsi.selectedtext;
  if str = '' then exit;
  MenuOpenAutotyperClick(Sender);
  MemoCopy.text:=str;
  MemoCopy.selectall;
  MemoCopy.CopyToClipboard;
  if screens[11] then screenEditor.ActiveEditor.PasteFromClipboard;
end;

procedure TFormMain.MenuDecreaseFontClick(Sender: TObject);
begin
  case (sender as TComponent).tag of
   -1: begin
         if MUDAnsi.font.size <= 6 then exit;
         MUDAnsi.font.size:=MUDAnsi.font.size-1;
       end;
    1: begin
         if MUDAnsi.font.size >= 20 then exit;
         MUDAnsi.font.size:=MUDAnsi.font.size+1;
       end;
  end;
  UpdateFonts;
  UpdateSendbar;
end;

procedure TFormMain.MenuBarWAYUpClick(Sender: TObject);
var newheight: integer;
begin
  if PanelScroll.height < 1 then exit;
  case (sender as TMenuItem).tag of
    -1: newheight:=scrollmin;
     1: newheight:=PanelLeftBar.height-barbuffer-PanelSend.height;
    else raise Exception.CreateFmt('TFormMain.MenuBarWAYUpClick: Invalid sender tag: %d', [(sender as TMenuItem).tag]);
  end;
  PanelScroll.height:=newheight;
  LEDScrollback.height:=newheight;
  UpdateScrollbackLabels;
end;

procedure TFormMain.MenuReconnectClick(Sender: TObject);
begin
  if Datawell.connected then begin
    if Datawell.TableOptions3.fieldbyname('L52').asboolean then begin
      if messagedlg('Break current connection?',
        mtconfirmation,[mbyes,mbcancel],0) = mrcancel then exit;
    end;    
    overrideclose:=true;
    Telnet.close;
    overrideclose:=false;
  end;
  if (Datawell.TableOptions3.fieldbyname('L45').asboolean and Datawell.connected2) then Telnet2.close;
  if PanelScroll.height > 0 then BtnCloseScrollback.click;
  FormMap.BtnChart.down:=false;
  FormMap.BtnFollow.down:=false;
  FormMap.UpdateCharting(0,true);
  SaveOptions(false);
  ClearSending;
  FormMap.formstyle:=fsnormal;
  DisableForms;
  FormLogin.LoginScreen(1,false);
end;

procedure TFormMain.MenuHomeAllClick(Sender: TObject);
begin
  case (sender as TMenuItem).tag of
    0: begin
         if screens[0] then begin
           screenChat.top:=0;
           screenChat.left:=0;
         end
         else begin
           Datawell.TableOptions.edit;
           Datawell.TableOptions.fieldbyname('ChatTop').asinteger:=0;
           Datawell.TableOptions.fieldbyname('ChatLeft').asinteger:=0;
           Datawell.TableOptions.post;
         end;
         if screens[1] then begin
           screenTell.top:=0;
           screenTell.left:=0;
         end
         else begin
           Datawell.TableOptions.edit;
           Datawell.TableOptions.fieldbyname('TellTop').asinteger:=0;
           Datawell.TableOptions.fieldbyname('TellLeft').asinteger:=0;
           Datawell.TableOptions.post;
         end;
         if screens[2] then begin
           screenRoom.top:=0;
           screenRoom.left:=0;
         end
         else begin
           Datawell.TableOptions3.edit;
           Datawell.TableOptions3.fieldbyname('I30').asinteger:=0;
           Datawell.TableOptions3.fieldbyname('I31').asinteger:=0;
           Datawell.TableOptions3.post;
         end;
         if screens[4] then begin
           screenImagery.top:=0;
           screenImagery.left:=0;
         end
         else begin
           Datawell.TableOptions.edit;
           Datawell.TableOptions.fieldbyname('ImageryTop').asinteger:=0;
           Datawell.TableOptions.fieldbyname('ImageryLeft').asinteger:=0;
           Datawell.TableOptions.post;
         end;
         if screens[6] then begin
           screenFiltered.top:=0;
           screenFiltered.left:=0;
         end
         else begin
           Datawell.TableOptions.edit;
           Datawell.TableOptions.fieldbyname('FilteredTop').asinteger:=0;
           Datawell.TableOptions.fieldbyname('FilteredLeft').asinteger:=0;
           Datawell.TableOptions.post;
         end;
         if screens[11] then begin
           screenEditor.top:=0;
           screenEditor.left:=0;
         end
         else begin
           Datawell.TableOptions.edit;
           Datawell.TableOptions.fieldbyname('EditorTop').asinteger:=0;
           Datawell.TableOptions.fieldbyname('EditorLeft').asinteger:=0;
           Datawell.TableOptions.post;
         end;
         FormMap.top:=0;
         FormMap.left:=0;
         if screens[10] then begin
           screenCanvas.top:=0;
           screenCanvas.left:=0;
         end
         else begin
           Datawell.TableOptions3.edit;
           Datawell.TableOptions3.fieldbyname('I12').asinteger:=0;
           Datawell.TableOptions3.fieldbyname('I13').asinteger:=0;
           Datawell.TableOptions3.post;
         end;
         top:=0;
         left:=0;
       end;
  999: begin
         top:=0;
         left:=0;
       end;
    1: begin
         if screens[1] then begin
           screenTell.top:=0;
           screenTell.left:=0;
           screenTell.show;
         end
         else begin
           Datawell.TableOptions.edit;
           Datawell.TableOptions.fieldbyname('TellTop').asinteger:=0;
           Datawell.TableOptions.fieldbyname('TellLeft').asinteger:=0;
           Datawell.TableOptions.post;
           LoadScreen(1);
         end;
       end;
    2: begin
         if screens[2] then begin
           screenRoom.top:=0;
           screenRoom.left:=0;
           screenRoom.show;
         end
         else begin
           Datawell.TableOptions3.edit;
           Datawell.TableOptions3.fieldbyname('I30').asinteger:=0;
           Datawell.TableOptions3.fieldbyname('I31').asinteger:=0;
           Datawell.TableOptions3.post;
           LoadScreen(2);
         end;
       end;
    3: begin
         if screens[11] then begin
           screenEditor.top:=0;
           screenEditor.left:=0;
           screenEditor.show;
         end
         else begin
           Datawell.TableOptions.edit;
           Datawell.TableOptions.fieldbyname('EditorTop').asinteger:=0;
           Datawell.TableOptions.fieldbyname('EditorLeft').asinteger:=0;
           Datawell.TableOptions.post;
           LoadScreen(11);
         end;
       end;
    4: begin
         if screens[4] then begin
           screenImagery.top:=0;
           screenImagery.left:=0;
           screenImagery.show;
         end
         else begin
           Datawell.TableOptions.edit;
           Datawell.TableOptions.fieldbyname('ImageryTop').asinteger:=0;
           Datawell.TableOptions.fieldbyname('ImageryLeft').asinteger:=0;
           Datawell.TableOptions.post;
           LoadScreen(4);
         end;
       end;
    7: begin
         if screens[0] then begin
           screenChat.top:=0;
           screenChat.left:=0;
           screenChat.show;
         end
         else begin
           Datawell.TableOptions.edit;
           Datawell.TableOptions.fieldbyname('ChatTop').asinteger:=0;
           Datawell.TableOptions.fieldbyname('ChatLeft').asinteger:=0;
           Datawell.TableOptions.post;
           LoadScreen(0);
         end;
       end;
    8: begin
         if screens[6] then begin
           screenFiltered.top:=0;
           screenFiltered.left:=0;
           screenFiltered.show;
         end
         else begin
           Datawell.TableOptions.edit;
           Datawell.TableOptions.fieldbyname('FilteredTop').asinteger:=0;
           Datawell.TableOptions.fieldbyname('FilteredLeft').asinteger:=0;
           Datawell.TableOptions.post;
           LoadScreen(6);
         end;
       end;
    10: begin
         FormMap.top:=0;
         FormMap.left:=0;
         FormMap.show;
       end;
    14: begin
         if screens[10] then begin
           screenCanvas.top:=0;
           screenCanvas.left:=0;
           screenCanvas.show;
         end
         else begin
           Datawell.TableOptions3.edit;
           Datawell.TableOptions3.fieldbyname('I12').asinteger:=0;
           Datawell.TableOptions3.fieldbyname('I13').asinteger:=0;
           Datawell.TableOptions3.post;
           LoadScreen(10);
         end;
       end;
  end;
end;

procedure TFormMain.BtnExitMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
var work: string;
begin
  if TimerMusic.enabled then exit;
  work:=TControl(sender).hint;
  if work = '' then work:=editingstring;
  if work = '' then work:=roomshortstring;
  LabelStatus.caption:=' '+work;
end;

procedure TFormMain.MenuFontClick(Sender: TObject);
begin
  DialogFont.font.assign(MUDAnsi.font);
  DialogFont.font.color:=Datawell.TableOptions.fieldbyname('ColorText').asinteger;
  if DialogFont.execute = false then exit;
  MUDAnsi.font.assign(DialogFont.font);
  UpdateFonts;
  UpdateSendbar;
end;

procedure TFormMain.DoStatusEvent(which: integer);
var action, sound, work: string;
begin
  if ImageEnableEvent.visible then exit;
  FigureStatusEvent(which,action,sound);
  if (action = '') and (sound = '') then exit;
  work:=action;
  if work = '' then work:='Sound: '+Datawell.FigureSound(sound);
  ParseMain(action,5);
  PlaySound(sound,1,0,0,false);
end;

procedure TFormMain.FigureStatusEvent(which: integer; var action: string; var sound: string);
const
   FILTER_STR = '(Master = %s) and (FGroup = ''%s'') and (Kind = %d)';
begin
  action:=''; sound:='';
  with Datawell.TableSEvents do begin
    filter := format(FILTER_STR, [Datawell.masterindex,
                                  Datawell.TableOptions.fieldbyname('FGroup').asstring,
                                  which]);
    filtered := true;
    active:=true;
  end;
  action:=Datawell.TableSEvents.fieldbyname('Action').asstring;
  sound:=Datawell.TableSEvents.fieldbyname('Sound').asstring;
end;

function TFormMain.TryAliasMacro(action: string; kind: integer): boolean;
begin
  result:=false;
  if action = '' then exit;
  if ProcessAlias(action,kind,true) then result:=true
  else if DoMacro(action,kind,true) then result:=true;
end;

procedure TFormMain.SetupEvents;
var
  i, j, g, m, p, s, filts: integer;
  groups: TStringList;
  work, varstring: string;
  inserted: boolean;
begin
  i:=0;
  filts:=0;
  EEvents.clear;
  EGroups.clear;
  EActions.clear;
  ESounds.clear;
  MUDAnsi.ClearTriggers;
  MUDAnsi.ClearFilters;
  Datawell.TableEventSort.Active := false;
  datawell.ExecuteArbitraryQuery('delete from eventsort');
  Datawell.TableEventSort.Active := true;
  if (FormMap.awaitingfailure) or (FormMap.refreshingroom) then begin
    if not FormMap.refreshingroom then begin
      for j:=1 to 5 do begin
        case j of
          1: work:=Datawell.TableGlobals.fieldbyname('Failure1').asstring;
          2: work:=Datawell.TableGlobals.fieldbyname('Failure2').asstring;
          3: work:=Datawell.TableGlobals.fieldbyname('Failure3').asstring;
          4: work:=Datawell.TableGlobals.fieldbyname('Failure4').asstring;
          5: work:=Datawell.TableGlobals.fieldbyname('Failure5').asstring;
        end;
        if work <> '' then begin
          Datawell.TableEventSort.append;
          Datawell.TableEventSort.fieldbyname('FGroup').asstring:='';
          Datawell.TableEventSort.fieldbyname('FEvent').asstring:=Datawell.subs(Datawell.specialcode,'',work);
          Datawell.TableEventSort.fieldbyname('FColor').asinteger:=
            Datawell.FigureColor(Datawell.TableOptions3.fieldbyname('I5').asinteger);
          Datawell.TableEventSort.fieldbyname('BColor').asinteger:=
            Datawell.FigureColor(Datawell.TableOptions3.fieldbyname('I6').asinteger);
          Datawell.TableEventSort.fieldbyname('FAction').asstring:='chartabort';
          Datawell.TableEventSort.fieldbyname('Soundfile').asstring:='';
          Datawell.TableEventSort.fieldbyname('CaseSensitive').asboolean:=false;
          Datawell.TableEventSort.fieldbyname('Filtered').asboolean:=false;
          Datawell.TableEventSort.fieldbyname('Terminal').asboolean:=false;
          Datawell.TableEventSort.fieldbyname('FOrder').asinteger:=j;
          Datawell.TableEventSort.post;
          next;
        end;
      end;
    end;
    for j:=1 to 5 do begin
      case j of
        1: work:=Datawell.TableGlobals.fieldbyname('S12').asstring;
        2: work:=Datawell.TableGlobals.fieldbyname('S13').asstring;
        3: work:=Datawell.TableGlobals.fieldbyname('S14').asstring;
        4: work:=Datawell.TableGlobals.fieldbyname('S15').asstring;
        5: work:=Datawell.TableGlobals.fieldbyname('S16').asstring;
      end;
      if work <> '' then begin
        inserted:=false;
        varstring:='';
        s:=pos('{@}',work);
        p:=pos('*',work);
        if p < 0 then varstring:=',{@}'
        else begin
          while p > 0 do begin
            if (p > s) and (not inserted) then begin
              varstring:=varstring+',{@}';
              inserted:=true;
            end;
            work:=copy(work,1,p-1)+Datawell.specialcode+copy(work,p+1,99999);
            p:=pos('*',work);
            varstring:=varstring+',<@>';
          end;
          if not inserted then varstring:=varstring+',{@}';
        end;
        delete(varstring,1,1);
        work:=Datawell.subs(Datawell.specialcode,'*',work);
        work:=Datawell.subs('{@}','*',work);
        Datawell.TableEventSort.append;
        Datawell.TableEventSort.fieldbyname('FGroup').asstring:='';
        Datawell.TableEventSort.fieldbyname('FEvent').asstring:=Datawell.subs(Datawell.specialcode,'',work);
        Datawell.TableEventSort.fieldbyname('FColor').asinteger:=
          Datawell.FigureColor(Datawell.TableOptions3.fieldbyname('I5').asinteger);
        Datawell.TableEventSort.fieldbyname('BColor').asinteger:=
          Datawell.FigureColor(Datawell.TableOptions3.fieldbyname('I6').asinteger);
        Datawell.TableEventSort.fieldbyname('FAction').asstring:='chartstubs'+varstring;
        Datawell.TableEventSort.fieldbyname('Soundfile').asstring:='';
        Datawell.TableEventSort.fieldbyname('CaseSensitive').asboolean:=false;
        Datawell.TableEventSort.fieldbyname('Filtered').asboolean:=false;
        Datawell.TableEventSort.fieldbyname('Terminal').asboolean:=false;
        Datawell.TableEventSort.fieldbyname('FOrder').asinteger:=j+5;
        Datawell.TableEventSort.post;
        next;
      end;
    end;
    //Short desc
    work:=Datawell.TableGlobals.fieldbyname('S20').asstring;
    inserted:=false;
    varstring:='';
    s:=pos('{$}',work);
    p:=pos('*',work);
    if p < 0 then varstring:=',{$}'
    else begin
      while p > 0 do begin
        if (p > s) and (not inserted) then begin
          varstring:=varstring+',{$}';
          inserted:=true;
        end;
        work:=copy(work,1,p-1)+Datawell.specialcode+copy(work,p+1,99999);
        p:=pos('*',work);
        varstring:=varstring+',<@>';
      end;
      if not inserted then varstring:=varstring+',{$}';
    end;
    delete(varstring,1,1);
    work:=Datawell.subs(Datawell.specialcode,'*',work);
    work:=Datawell.subs('{$}','*',work);
    if work <> '' then begin
      Datawell.TableEventSort.append;
      Datawell.TableEventSort.fieldbyname('FGroup').asstring:='';
      Datawell.TableEventSort.fieldbyname('FEvent').asstring:=Datawell.subs(Datawell.specialcode,'',work);
      Datawell.TableEventSort.fieldbyname('FColor').asinteger:=
        Datawell.FigureColor(Datawell.TableOptions3.fieldbyname('I5').asinteger);
      Datawell.TableEventSort.fieldbyname('BColor').asinteger:=
        Datawell.FigureColor(Datawell.TableOptions3.fieldbyname('I6').asinteger);
      Datawell.TableEventSort.fieldbyname('FAction').asstring:='chartshort'+varstring;
      Datawell.TableEventSort.fieldbyname('Soundfile').asstring:='';
      Datawell.TableEventSort.fieldbyname('CaseSensitive').asboolean:=false;
      Datawell.TableEventSort.fieldbyname('Filtered').asboolean:=false;
      Datawell.TableEventSort.fieldbyname('Terminal').asboolean:=false;
      Datawell.TableEventSort.fieldbyname('FOrder').asinteger:=999;
      Datawell.TableEventSort.post;
    end;
  end;
  if not ImageEnableEvent.visible then begin
    m:=1000;
    groups:=TStringList.create;
    Datawell.explode(Datawell.TableOptions2.fieldbyname('Groups').asstring,',',groups);
    for g:=0 to groups.count-1 do begin
      with Datawell.TableEvents do begin
        filter := format('(Master = %s) and (FGROUP = ''%s'')', [Datawell.masterindex, groups[g]]);
        filtered := true;
        active:=true;
        first;
        while not EOF do begin
          if copy(fieldbyname('FAction').asstring,1,1) <> '|' then begin
            Datawell.TableEventSort.append;
            Datawell.TableEventSort.fieldbyname('FGroup').asstring:=groups[g];
            Datawell.TableEventSort.fieldbyname('FEvent').asstring:=
              fieldbyname('FEvent').asstring;
            Datawell.TableEventSort.fieldbyname('FColor').asinteger:=
              fieldbyname('FColor').asinteger;
            Datawell.TableEventSort.fieldbyname('BColor').asinteger:=
              fieldbyname('BColor').asinteger;
            Datawell.TableEventSort.fieldbyname('FAction').asstring:=
              fieldbyname('FAction').asstring;
            Datawell.TableEventSort.fieldbyname('Soundfile').asstring:=
              fieldbyname('Soundfile').asstring;
            Datawell.TableEventSort.fieldbyname('CaseSensitive').asboolean:=
              fieldbyname('CaseSensitive').asboolean;
            Datawell.TableEventSort.fieldbyname('Filtered').asboolean:=
              fieldbyname('Filtered').asboolean;
            Datawell.TableEventSort.fieldbyname('FRetain').asboolean:=
              fieldbyname('FRetain').asboolean;
            Datawell.TableEventSort.fieldbyname('Terminal').asboolean:=
              fieldbyname('Terminal').asboolean;
            Datawell.TableEventSort.fieldbyname('FOrder').asinteger:=
              fieldbyname('FOrder').asinteger+m;
            Datawell.TableEventSort.fieldbyname('Script').assign(fieldbyname('Script'));
            Datawell.TableEventSort.post;
          end;
          next;
        end;
      end;
      inc(m,1000);
    end;
    groups.free;
    datawell.TableEvents.filter := format('(Master = %s)', [Datawell.masterindex]);
  end;
  with Datawell.TableEventSort do begin
    first;
    while not EOF do begin
      MUDAnsi.Triggers[i]:=fieldbyname('FEvent').asstring;
      MUDAnsi.TriggerColor[i]:=Datawell.ColorFigure(fieldbyname('FColor').asinteger);
      MUDAnsi.TriggerBGColor[i]:=Datawell.ColorFigure(fieldbyname('BColor').asinteger);
      MUDAnsi.TriggerTerminal[i]:=fieldbyname('Terminal').asboolean;
      MUDAnsi.TriggerCaseInsensitive[i]:=not fieldbyname('CaseSensitive').asboolean;
      MUDAnsi.TriggerFilter[i]:=fieldbyname('Filtered').asboolean;
      MUDAnsi.TriggerRetain[i]:=fieldbyname('FRetain').asboolean;
      EEvents.add(fieldbyname('FEvent').asstring);
      EGroups.add(fieldbyname('FGroup').asstring);
      EActions.add(fieldbyname('FAction').asstring);
      ESounds.add(fieldbyname('Soundfile').asstring);
      //Patchwork filter crap
      if fieldbyname('Filtered').asboolean then begin
        MUDAnsi.FiltersCaseInsensitive[filts]:=not fieldbyname('CaseSensitive').asboolean;
        if MUDAnsi.FiltersCaseInsensitive[filts] then
          MUDAnsi.Filters[filts]:=lowercase(Datawell.TableEventSort.fieldbyname('FEvent').asstring)
        else MUDAnsi.Filters[filts]:=Datawell.TableEventSort.fieldbyname('FEvent').asstring;
        MUDAnsi.FiltersRetain[filts]:=Datawell.TableEventSort.fieldbyname('FRetain').asboolean;
        inc(filts);
      end;
      inc(i);
      if i >= 249 then break;
      next;
    end;
  end;
end;

procedure TFormMain.MUDAnsiTrigger(index: Integer; variables: strarray);
const
   FILTER_STR = '(MASTER = %s) and (FGroup = ''%s'') and (FEvent = ''%s'')';
//variables[0] should always be 'OK'...if not, its buggy
var
  i: integer;
  vars: TStringList;
  script: string;
begin
  if eventsdone >= Datawell.TableGlobals.fieldbyname('MaxEvents').asinteger then begin
    PanelLeftBar.color:=clred;
    exit;
  end;
  inc(eventsdone);
  PlaySound(ESounds[index],1,0,0,false);
//Check charting
  if copy(EActions[index],1,5) = 'chart' then begin
    if copy(EActions[index],6,5) = 'abort' then FormMap.AbortChart
    else if copy(EActions[index],6,5) = 'stubs' then begin
      if variables[0] = 'OK' then begin
        vars:=TStringList.create;
        Datawell.Explode(copy(EActions[index],11,99999),',',vars);
        for i:=0 to vars.count-1 do begin
          if vars[i] = '{@}' then FormMap.CollectStubs(variables[i+1]);
        end;
        vars.free;
      end;
      if Datawell.TableGlobals.fieldbyname('L2').asboolean then begin
        if TimerChart.enabled = false then TimerChart.enabled:=true;
      end;
    end
    else if copy(EActions[index],6,5) = 'short' then begin
      if variables[0] = 'OK' then begin
        vars:=TStringList.create;
        Datawell.Explode(copy(EActions[index],11,99999),',',vars);
        for i:=0 to vars.count-1 do begin
          if vars[i] = '{$}' then begin
            if FormMap.awaitinglabel = '' then FormMap.awaitinglabel:=variables[i+1];
          end;
        end;
        vars.free;
      end;
      if Datawell.TableGlobals.fieldbyname('L2').asboolean then begin
        if TimerChart.enabled = false then TimerChart.enabled:=true;
      end;
    end;
  end
//Update Variables (if there are any)
  else begin
    if EActions[index] <> '' then begin
      if variables[0] = 'OK' then begin
        vars:=TStringList.create;
        Datawell.Explode(EActions[index],',',vars);
        for i:=0 to vars.count-1 do begin
          if vars[i] <> '<@>' then begin
            if Datawell.TableOptions3.fieldbyname('L15').asboolean then
              variables[i+1]:=lowercase(variables[i+1]);
            Datawell.UpdateVariable('@'+vars[i],variables[i+1]);
            UpdateCanvasVariable('@'+vars[i],variables[i+1]);
          end;
        end;
        vars.free;
      end;
    end;
//Cycle EActions
    script := Datawell.TableEvents.Lookup(
       'Master;FGroup;FEvent',
       VarArrayOf([Datawell.masterindex, EGroups[index], EEvents[index]]),
       'script');
    if script <> '' then
       Scripts.RunScript(script);
  end;
end;

procedure TFormMain.MenuPasteClick(Sender: TObject);
var
  i: integer;
  work: string;
begin
  MemoPaste.lines.clear;
  MemoPaste.pastefromclipboard;
  for i:=0 to MemoPaste.lines.count-1 do begin
    work:=MemoPaste.lines[i];
    ParseMain(work,6);
  end;
end;

procedure TFormMain.MenuClearScrollbackClick(Sender: TObject);
begin
  if PanelScroll.height > 0 then BtnCloseScrollback.click;
  Scrollback.clear;
  MUDAnsi.clear;
  UpdateTotalLabel;
end;

procedure TFormMain.EnemyImage(data: string);
begin
  ShowImage(data,ImageEnemyName.hint);
end;

procedure TFormMain.ShowImage(filename, text: string);
var
  GIF: TGIFImage;
  Bitmap: TBitmap;
  dir: string;
  isbmp, isgif: boolean;
begin
  if (not screens[4]) and
    (not Datawell.TableOptions2.fieldbyname('AutoShowImagery').asboolean) then exit;
  if panicking then exit;
  isbmp:=false;
  isgif:=false;
  if filename = '' then begin
    if screens[4] then begin
      screenImagery.image.hide;
      screenImagery.LabelText.caption:=text
    end;
    exit;
  end;
  dir:=Datawell.getimagedir+'\';
  filename:=lowercase(filename);
  //if file exists, then print it out
  if fileexists(filename) then begin
    //File does exist, check if it's a .bmp or a .gif
    if copy(filename,length(filename)-3,4) = '.bmp' then isbmp:=true
    else if copy(filename,length(filename)-3,4) = '.gif' then isgif:=true;
  end
  else begin
    //File doesn't exist
    //Check the media dir for the file
    filename:=dir+filename;
    if fileexists(filename) then begin
      //File does exist, check if it's a .bmp or a .gif
      if copy(filename,length(filename)-3,4) = '.bmp' then isbmp:=true
      else if copy(filename,length(filename)-3,4) = '.gif' then isgif:=true;
    end
    else begin
      //File doesn't exist
      //See if there's a .bmp file with that name
      if fileexists(filename+'.bmp') then begin
        filename:=filename+'.bmp';
        isbmp:=true;
      end
      else if fileexists(filename+'.gif') then begin
        filename:=filename+'.gif';
        isgif:=true;
      end;
    end;
  end;
  if (not isbmp) and (not isgif) then exit;
  //If the file is a .gif, convert it to a .bmp
  if isgif then begin
    try GIF:=TGIFImage.Create; try GIF.LoadFromFile(filename);
      Bitmap:=TBitmap.Create; try Bitmap.Assign(GIF);
      Bitmap.SaveToFile(Datawell.exedir+'/xxtmp.bmp');
    finally Bitmap.Free; end; finally GIF.Free; end; finally end;
    filename:=Datawell.exedir+'/xxtmp.bmp';
  end;
  LoadScreen(4);
  if screens[4] then screenImagery.LabelText.caption:=text;
  with screenImagery do begin
    PanelMP.width:=0;
    PanelAVI.hide;
    avis.clear;
    Image.picture.loadfromfile(filename);
    image.show;
  end;
  if fileexists(Datawell.exedir+'/xxtmp.bmp') then
    deletefile(Datawell.exedir+'/xxtmp.bmp');
  EditSend.setfocus;
end;

procedure TFormMain.ShowAVI(filename, text: string; h, w: integer; dorepeat: boolean);
var
  dir: string;
  newh, neww: integer;
begin
  if (not screens[4]) and
    (not Datawell.TableOptions2.fieldbyname('AutoShowImagery').asboolean) then exit;
  if screens[4] then screenImagery.LabelText.caption:=text;
  if filename = '' then begin
    if screens[4] then screenImagery.PanelAVI.hide;
    exit;
  end;
  dir:=Datawell.getimagedir;
  filename:=lowercase(filename);
  //Check if file exists
  if not fileexists(filename) then begin
    //File doesn't exist
    //Check the media dir for the file
    if fileexists(filename+'.avi') then filename:=filename+'.avi'
    else begin
      filename:=dir+filename;
      if not fileexists(filename) then begin
        //File doesn't exist
        //See if there's an .avi file with that name
        if fileexists(filename+'.avi') then filename:=filename+'.avi';
      end;
    end;
  end;
  if not fileexists(filename) then exit;
  LoadScreen(4);
  if screens[4] then screenImagery.LabelText.caption:=text;
  if Datawell.TableOptions3.fieldbyname('L23').asboolean then begin
    newh:=h+57;
    neww:=w+34;
    if newh > Datawell.TableOptions3.fieldbyname('I17').asinteger then
      newh:=Datawell.TableOptions3.fieldbyname('I17').asinteger;
    if neww > Datawell.TableOptions3.fieldbyname('I18').asinteger then
      neww:=Datawell.TableOptions3.fieldbyname('I18').asinteger;
    if newh > screenImagery.height then screenImagery.height:=newh;
    if neww > screenImagery.width then screenImagery.width:=neww;
  end;
  with screenImagery do begin
    PanelMP.width:=35;
    MenuAutoRepeat.checked:=dorepeat;
    PanelAVI.show;
    avis.add(filename);
    DoPlay;
  end;
  EditSend.setfocus;
end;

procedure TFormMain.EditSendChange(Sender: TObject);
var amt: integer;
begin
  if PanelSends.visible then PanelSends.hide;
//Auto-expand
  if Datawell.TableOptions2.fieldbyname('AutoExpand').asboolean then begin
    amt:=EditSend.lines.count;
    if amt < 1 then amt:=1;
    if amt > 15 then amt:=15;
    editsendlines:=amt;
    EditSend.height:=12+(editsendlines*(editsendheight+6));
  end
  else EditSend.height:=24;
  PanelSend.height:=EditSend.height;
  PanelLED.height:=EditSend.height;
  ImageLeftBarBottom.top:=PanelLED.height-2;
//Reposition Scrollbar if necessary
  if PanelScroll.height > PanelLeftBar.height-barbuffer-PanelSend.height then begin
    PanelScroll.height:=PanelLeftBar.height-barbuffer-PanelSend.height;
    Datawell.TableOptions.edit;
    Datawell.TableOptions.fieldbyname('ScrollPosition').asinteger:=PanelScroll.height;
    Datawell.TableOptions.post;
    LEDScrollback.height:=PanelScroll.height;
  end;
//Reposition History windows
  EditHistory.top:=PanelMain.top+PanelMain.height-PanelSend.height-22;
  ListHistory.top:=EditHistory.top-94;
  ListHistoryIndex.top:=ListHistory.top;
  EditSearch.top:=EditHistory.top-114;
  PanelDownload.top:=EditHistory.top-11;
  if bypass then exit;
  if EditSend.text = '' then exit;
  HistorySearch:=EditSend.text;
  ClearHistoryVars;
  CloseHistory;
end;

function TFormMain.Wildcard(data, wild: string; amt: integer): string;
var
  j: integer;
  temp, wild1, wild2, wild3, wild4, wild5, wildx: string;
  wtotal, w1, w2, w3, w4, w5, w6: integer;
begin
  w1:=0; w2:=0; w3:=0; w4:=0; w5:=0; w6:=0;
  wild1:=''; wild2:=''; wild3:=''; wild4:=''; wild5:=''; wildx:='';
  data:=Datawell.subs('~$',Datawell.specialcode,data);
  result:=data;
  if wild = '' then begin
    result:=Datawell.subs('$1','',result);
    result:=Datawell.subs('$2','',result);
    result:=Datawell.subs('$3','',result);
    result:=Datawell.subs('$4','',result);
    result:=Datawell.subs('$5','',result);
    result:=Datawell.subs('$','',result);
    result:=Datawell.subs(Datawell.specialcode,'$',result);
    result:=Datawell.CutTrailingSpaces(result);
    exit;
  end;
  j:=pos(' ',wild);
  if j < 1 then wild1:=wild
  else begin
    wild1:=copy(wild,1,j-1);
    delete(wild,1,j);
    j:=pos(' ',wild);
    if j < 1 then wild2:=wild
    else begin
      wild2:=copy(wild,1,j-1);
      delete(wild,1,j);
      j:=pos(' ',wild);
      if j < 1 then wild3:=wild
      else begin
        wild3:=copy(wild,1,j-1);
        delete(wild,1,j);
        j:=pos(' ',wild);
        if j < 1 then wild4:=wild
        else begin
          wild4:=copy(wild,1,j-1);
          delete(wild,1,j);
          wild5:=wild;
        end;
      end;
    end;
  end;
  temp:=Datawell.subs('$1',wild1,data);
  if temp <> data then w1:=1; data:=temp;
  temp:=Datawell.subs('$2',wild2,data);
  if temp <> data then w2:=1; data:=temp;
  temp:=Datawell.subs('$3',wild3,data);
  if temp <> data then w3:=1; data:=temp;
  temp:=Datawell.subs('$4',wild4,data);
  if temp <> data then w4:=1; data:=temp;
  temp:=Datawell.subs('$5',wild5,data);
  if temp <> data then w5:=1; data:=temp;
  wildx:=wild1;
  if wild2 <> '' then wildx:=wildx+' '+wild2;
  if wild3 <> '' then wildx:=wildx+' '+wild3;
  if wild4 <> '' then wildx:=wildx+' '+wild4;
  if wild5 <> '' then wildx:=wildx+' '+wild5;
  temp:=Datawell.subs('$',wildx,data);
  if temp <> data then w6:=1; data:=temp;
  wtotal:=w1+w2+w3+w4+w5+w6;
  if (wtotal < 1) and (amt = 1) then begin
    if wild1 <> '' then data:=data+' '+wild1;
    if wild2 <> '' then data:=data+' '+wild2;
    if wild3 <> '' then data:=data+' '+wild3;
    if wild4 <> '' then data:=data+' '+wild4;
    if wild5 <> '' then data:=data+' '+wild5;
  end;
  result:=data;
  result:=Datawell.subs(Datawell.specialcode,'$',result);
  result:=Datawell.CutTrailingSpaces(result);
end;

procedure TFormMain.MenuHelpTopicsClick(Sender: TObject);
begin
  Datawell.Help('overview');
end;

procedure TFormMain.MUDAnsiCopyToAutotyper(DATA: string);
begin
  MenuOpenAutotyperClick(nil);
  MemoCopy.text:=DATA;
  MemoCopy.selectall;
  MemoCopy.CopyToClipboard;
  if screens[11] then screenEditor.ActiveEditor.PasteFromClipboard;
end;

procedure TFormMain.MenuNicknamesClick(Sender: TObject);
var form: TFormNicknames;
begin
  form:=TFormNicknames.create(self);
  form.showmodal;
  form.free;
end;

procedure TFormMain.MUDAnsiFilter(DATA: string);
begin
  with Datawell.TableFiltered do begin
    last;
    append;
    fieldbyname('Text').asstring:=DATA;
    post;
  end;
  if not Datawell.TableOptions2.fieldbyname('DisableAliasLED').asboolean then begin
    PanelLED.color:=clred;
    TimerLED.enabled:=false;
    TimerLED.interval:=750;
    TimerLED.enabled:=true;
  end;
  UpdateFilteredCount;
end;

function TFormMain.FigureTimeString: string;
var hours, minutes, seconds: integer;
begin
  result:='';
  seconds:=onlinetime;
  hours:=seconds div 3600;
  seconds:=seconds-(hours*3600);
  minutes:=seconds div 60;
//  seconds:=seconds-(minutes*60);
  if hours < 10 then result:=concat(result,'0');
  result:=concat(result,inttostr(hours)+':');
  if minutes < 10 then result:=concat(result,'0');
  result:=concat(result,inttostr(minutes));
end;

procedure TFormMain.UpdateFilteredCount;
var amt: integer;
begin
  amt:=Datawell.TableFiltered.recordcount;
  if amt > 0 then LEDFilter.brush.color:=clred
  else LEDFilter.brush.color:=clgray;
  LEDImageFilter.hint:='Number of system messages: '+inttostr(amt);
end;

procedure TFormMain.BtnTellClick(Sender: TObject);
begin
  case (sender as TSpeedButton).tag of
    1: MenuShowTell.click;
    3: MenuShowImagery.click;
    6: MenuShowChat.click;
    10: MenuShowCartographer.click;
    14: MenuShowCanvas.click;
  end;
end;

procedure TFormMain.BtnCloseToolbarClick(Sender: TObject);
begin
  case TSpeedButton(sender).tag of
    1: MenuShowToolbar.click;
    2: MenuShowStatusbar.click;
    3: MenuShowHPBar.click;
    4: MenuShowHP2Bar.click;
    5: MenuShowHP3Bar.click;
    6: MenuShowHP4Bar.click;
    7: begin
         if adcycled >= adcycledmax then SpecialMessage('');
       end;
  end;
end;

procedure TFormMain.TimerDelayTimer(Sender: TObject);
begin
  dec(delaycounter);
  if delaycounter < 1 then begin
    LabelDelay.hide;
    HideClocks;
    clockphase:=0;
    exit;
  end;
  inc(clockphase);
  if clockphase > 8 then clockphase:=1;
  case clockphase of
    1: begin ImageClock1.show; ImageClock1.bringtofront; end;
    2: begin ImageClock8.show; ImageClock8.bringtofront; end;
    3: begin ImageClock7.show; ImageClock7.bringtofront; end;
    4: begin ImageClock6.show; ImageClock6.bringtofront; end;
    5: begin ImageClock5.show; ImageClock5.bringtofront; end;
    6: begin ImageClock4.show; ImageClock4.bringtofront; end;
    7: begin ImageClock3.show; ImageClock3.bringtofront; end;
    8: begin ImageClock2.show; ImageClock2.bringtofront; end;
  end;
  LabelDelay.caption:=inttostr(delaycounter);
end;

procedure TFormMain.HideClocks;
begin
  ImageClock1.hide;
  ImageClock2.hide;
  ImageClock3.hide;
  ImageClock4.hide;
  ImageClock5.hide;
  ImageClock6.hide;
  ImageClock7.hide;
  ImageClock8.hide;
end;

procedure TFormMain.ClearSending;
begin
  Sends.clear;
  HideClocks;
  LabelDelay.hide;
  TimerDelay.enabled:=false;
  TimerSend.enabled:=false;
  TimerSend.interval:=1;
  clockphase:=0;
  delaycounter:=0;
  doingsend:=false;
  UpdateLabelBuffered;
end;

procedure TFormMain.UpdateLabelBuffered;
begin
  if Sends.count < 1 then begin
    LabelBuffered.caption:='';
    BtnShowSends.enabled:=false;
    if PanelSends.visible then PanelSends.hide;
  end
  else begin
    LabelBuffered.caption:='('+inttostr(Sends.count)+')';
    BtnShowSends.enabled:=true;
  end;
end;

procedure TFormMain.UpdateTotalLabel;
begin
  LabelTotal.caption:=inttostr(MUDAnsi.flines.count);
  if PanelScroll.height > 0 then UpdateScrollbackLabels;
end;

procedure TFormMain.UpdateScrollbackLabels;
var top, bot: integer;
begin
  PanelScrollBottom.top:=PanelSeparator.top-65;
  bot:=Scrollback.curscrollpos+Scrollback.FClientSize.y;
  if bot > Scrollback.flines.count then bot:=Scrollback.flines.count;
  LabelBottom.caption:=inttostr(bot);
  if bot = Scrollback.flines.count then LabelBottom.color:=clsilver
  else LabelBottom.color:=clwhite;
  LabelSTotal.caption:=inttostr(Scrollback.flines.count);
  top:=Scrollback.curscrollpos+1;
  if top > bot then top:=bot;
  if top > Datawell.TableOptions.fieldbyname('Scroll').asinteger then
    top:=Datawell.TableOptions.fieldbyname('Scroll').asinteger;
  LabelTop.caption:=inttostr(top);
  if Scrollback.curscrollpos = 0 then LabelTop.color:=clsilver
  else LabelTop.color:=clwhite;
end;

procedure TFormMain.MenuCustomizeToolbarClick(Sender: TObject);
var form: TFormToolbar;
begin
  if not Datawell.CheckRinged(true,'toolbar customization') then exit;
  form:=TFormToolbar.create(self);
  form.Setup;
  form.showmodal;
  form.free;
  UpdateToolbar;
end;

procedure TFormMain.UpdateToolbar;
var
  data, work: string;
  i, pos: integer;
  buttons, positions: TStringList;
begin
  buttons:=TStringList.create;
  positions:=TStringList.create;
  pos:=2;
  data:=Datawell.TableOptions.fieldbyname('Toolbar').asstring;
  while length(data) > 0 do begin
    if data[1] = '_' then inc(pos,3)
    else begin
      positions.add(inttostr(pos));
      buttons.add(data[1]);
      inc(pos,BtnExit.width);
    end;
    delete(data,1,1);
  end;
  HideButtons;
  for i:=0 to buttons.count-1 do PositionButton(buttons[i],positions[i]);
  buttons.free;
  positions.free;
  UpdateRecordbar;
  work:=Datawell.TableOptions3.fieldbyname('Tool1').asstring;
  if work = '' then work:='<unassigned>'; work:=copy(work,1,50); m1.hint:=work;
  work:=Datawell.TableOptions3.fieldbyname('Tool2').asstring;
  if work = '' then work:='<unassigned>'; work:=copy(work,1,50); m2.hint:=work;
  work:=Datawell.TableOptions3.fieldbyname('Tool3').asstring;
  if work = '' then work:='<unassigned>'; work:=copy(work,1,50); m3.hint:=work;
  work:=Datawell.TableOptions3.fieldbyname('Tool4').asstring;
  if work = '' then work:='<unassigned>'; work:=copy(work,1,50); m4.hint:=work;
  work:=Datawell.TableOptions3.fieldbyname('Tool5').asstring;
  if work = '' then work:='<unassigned>'; work:=copy(work,1,50); m5.hint:=work;
  work:=Datawell.TableOptions3.fieldbyname('Tool6').asstring;
  if work = '' then work:='<unassigned>'; work:=copy(work,1,50); m6.hint:=work;
  work:=Datawell.TableOptions3.fieldbyname('Tool7').asstring;
  if work = '' then work:='<unassigned>'; work:=copy(work,1,50); m7.hint:=work;
  work:=Datawell.TableOptions3.fieldbyname('Tool8').asstring;
  if work = '' then work:='<unassigned>'; work:=copy(work,1,50); m8.hint:=work;
  work:=Datawell.TableOptions3.fieldbyname('Tool9').asstring;
  if work = '' then work:='<unassigned>'; work:=copy(work,1,50); m9.hint:=work;
  work:=Datawell.TableOptions3.fieldbyname('Tool10').asstring;
  if work = '' then work:='<unassigned>'; work:=copy(work,1,50); m10.hint:=work;
  work:=Datawell.TableOptions3.fieldbyname('Tool11').asstring;
  if work = '' then work:='<unassigned>'; work:=copy(work,1,50); m11.hint:=work;
  work:=Datawell.TableOptions3.fieldbyname('Tool12').asstring;
  if work = '' then work:='<unassigned>'; work:=copy(work,1,50); m12.hint:=work;
end;

procedure TFormMain.HideButtons;
begin
  BtnExit.hide;
  BtnReconnect.hide;
  BtnLock.hide;
  BtnAliases.hide;
  BtnMacros.hide;
  BtnQuickchars.hide;
  BtnEvents.hide;
  BtnNicknames.hide;
  BtnViewFiltered.hide;
  BtnAutotyper.hide;
  BtnAutotype.hide;
  BtnCopy.hide;
  BtnCopyToAutotyper.hide;
  BtnPaste.hide;
  BtnReduceFont.hide;
  BtnIncreaseFont.hide;
  BtnFont.hide;
  BtnOptions.hide;
  BtnTell.hide;
  BtnImagery.hide;
  BtnHelp.hide;
  BtnPanic.hide;
  BtnClearScrollback.hide;
  BtnToolbar.hide;
  BtnScrollback.hide;
  BtnEscape.hide;
  BtnDisconnect.hide;
  BtnClearKeyhistory.hide;
  BtnCapture.hide;
  BtnGroups.hide;
  BtnDisplay.hide;
  BtnChat.hide;
  BtnLog.hide;
  BtnClearFiltered.hide;
  BtnBASE.hide;
  BtnTicker.hide;
  BtnFind.hide;
  BtnNext.hide;
  BtnPrior.hide;
  BtnJumpstart.hide;
  BtnDownloadA.hide;
  BtnDownloadF.hide;
  BtnClearDownload.hide;
  BtnPasteCursor.hide;
  BtnUpload.hide;
  BtnMapper.hide;
  BtnVars.hide;
  m1.hide;
  m2.hide;
  m3.hide;
  m4.hide;
  m5.hide;
  m6.hide;
  m7.hide;
  m8.hide;
  m9.hide;
  m10.hide;
  m11.hide;
  m12.hide;
  BtnMap.hide;
  BtnQuickEvent.hide;
  BtnMusicPlay.hide;
  BtnMusicPause.hide;
  BtnMusicRewind.hide;
  BtnCanvas.hide;
  BtnMusicOpen.hide;
  BtnSecondary.hide;
  BtnSecondaryDisconnect.hide;
  BtnSecondaryReverse.hide;
  BtnHotkeys.hide;
  BtnIO.hide;
  BtnSendTextFile.hide;
  BtnMusicPrevious.hide;
  BtnMusicNext.hide;
  BtnMusicLoad.hide;
  BtnMusicFirst.hide;
  BtnMusicLast.hide;
  BtnAutoscribble.hide;
end;

procedure TFormMain.PositionButton(but, pos: string);
var button: TSpeedButton;
begin
  if but = 'a' then button:=BtnExit
  else if but = 'b' then button:=BtnReconnect
  else if but = 'c' then button:=BtnLock
  else if but = 'd' then button:=BtnAliases
  else if but = 'e' then button:=BtnMacros
  else if but = 'f' then button:=BtnQuickchars
  else if but = 'g' then button:=BtnEvents
  else if but = 'h' then button:=BtnNicknames
  else if but = 'j' then button:=BtnViewFiltered
  else if but = 'k' then button:=BtnAutotyper
  else if but = 'l' then button:=BtnAutotype
  else if but = 'm' then button:=BtnCopy
  else if but = 'n' then button:=BtnCopyToAutotyper
  else if but = 'o' then button:=BtnPaste
  else if but = 'p' then button:=BtnReduceFont
  else if but = 'q' then button:=BtnIncreaseFont
  else if but = 'r' then button:=BtnFont
  else if but = 's' then button:=BtnOptions
  else if but = 't' then button:=BtnTell
  else if but = 'v' then button:=BtnImagery
  else if but = 'w' then button:=BtnHelp
  else if but = 'x' then button:=BtnPanic
  else if but = 'y' then button:=BtnClearScrollback
  else if but = 'z' then button:=BtnToolbar
  else if but = '1' then button:=BtnScrollback
  else if but = '2' then button:=BtnEscape
  else if but = '4' then button:=BtnDisconnect
  else if but = '5' then button:=BtnClearKeyhistory
  else if but = '8' then button:=BtnCapture
  else if but = '9' then button:=BtnGroups
  else if but = 'S' then button:=BtnDisplay
  else if but = 'T' then button:=BtnChat
  else if but = 'U' then button:=BtnLog
  else if but = 'W' then button:=BtnClearFiltered
  else if but = 'X' then button:=BtnBASE
  else if but = 'Y' then button:=BtnTicker
  else if but = 'Z' then button:=BtnFind
  else if but = '!' then button:=BtnNext
  else if but = '@' then button:=BtnPrior
  else if but = '#' then button:=BtnJumpstart
  else if but = 'A' then button:=m1
  else if but = 'B' then button:=m2
  else if but = 'C' then button:=m3
  else if but = 'D' then button:=m4
  else if but = 'E' then button:=m5
  else if but = 'F' then button:=m6
  else if but = 'G' then button:=m7
  else if but = 'H' then button:=m8
  else if but = 'I' then button:=m9
  else if but = 'J' then button:=m10
  else if but = 'K' then button:=m11
  else if but = 'L' then button:=m12
  else if but = 'M' then button:=BtnDownloadA
  else if but = 'N' then button:=BtnDownloadF
  else if but = 'O' then button:=BtnClearDownload
  else if but = 'P' then button:=BtnPasteCursor
  else if but = 'Q' then button:=BtnUpload
  else if but = 'R' then button:=BtnMapper
  else if but = '-' then button:=BtnVars
  else if but = '|' then button:=BtnMap
  else if but = '>' then button:=BtnQuickEvent
  else if but = ',' then button:=BtnMusicPlay
  else if but = '.' then button:=BtnMusicPause
  else if but = '?' then button:=BtnMusicRewind
  else if but = '$' then button:=BtnMusicOpen
  else if but = '/' then button:=BtnCanvas
  else if but = '[' then button:=BtnSecondary
  else if but = ']' then button:=BtnSecondaryDisconnect
  else if but = '{' then button:=BtnSecondaryReverse
  else if but = '}' then button:=BtnHotkeys
  else if but = ':' then button:=BtnIO
  else if but = ';' then button:=BtnSendTextFile
  else if but = '%' then button:=BtnMusicPrevious
  else if but = '^' then button:=BtnMusicNext
  else if but = '&' then button:=BtnMusicLoad
  else if but = '*' then button:=BtnMusicFirst
  else if but = '(' then button:=BtnMusicLast
  else if but = '<' then button:=BtnAutoscribble
  else exit;
  button.show;
  button.top:=2;
  button.left:=strtoint(pos)+PanelSecondary.width;
end;

procedure TFormMain.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
var
  newheight: integer;
begin
  if (key = vk_Left) or (key = vk_Right) or (key = vk_End) then begin
    ParsingI:=Parsing.count-1;
    ParsePos:=0;
  end;
  if (key = vk_Home) or (key = vk_End) or
    ((shift = [ssshift]) and ((key = vk_Left) or (key = vk_Right))) then homed:=true;
  if key = vk_Up then begin
    if activecontrol <> EditSend then exit;
    if (EditSend.selstart = 0) and (EditSend.sellength > 0) then
      EditSend.text:=copy(EditSend.text,1,EditSend.sellength);
    if (EditSend.lines.count > 1) and
      ((EditSend.sellength < length(EditSend.text)) or (shift = [ssshift])) then exit;
    if shift = [ssshift] then begin
      if PanelScroll.height < 1 then exit;
      newheight:=PanelScroll.height-5;
      if newheight < scrollmin then newheight:=scrollmin;
      if newheight > PanelLeftBar.height-barbuffer-PanelSend.height then
        newheight:=PanelLeftBar.height-barbuffer-PanelSend.height;
      PanelScroll.height:=newheight;
      LEDScrollback.height:=newheight;
      UpdateScrollbackLabels;
      exit;
    end;
    key:=0;
    if shift = [ssctrl] then begin
      ScrollUp(1);
      exit;
    end;
    if ListHistory.visible then begin
      UpHistory;
      exit;
    end;
    if HistoryI = History.count then HistorySearch:=EditSend.text;
    if HistorySearch <> '' then begin
      SearchHistory('back');
      exit;
    end;
    dec(HistoryI);
    if HistoryI < 0 then begin
      HistoryI:=0;
      exit;
    end;
    RetrieveHistory;
    exit;
  end;
  if key = vk_Down then begin
    if activecontrol <> EditSend then exit;
    if (EditSend.selstart = 0) and (EditSend.sellength > 0) then
      EditSend.text:=copy(EditSend.text,1,EditSend.sellength);
    if (EditSend.lines.count > 1) and
      ((EditSend.sellength < length(EditSend.text)) or (shift = [ssshift])) then exit;
    if shift = [ssshift] then begin
      if PanelScroll.height < 1 then exit;
      newheight:=PanelScroll.height+5;
      if newheight < scrollmin then newheight:=scrollmin;
      if newheight > PanelLeftBar.height-barbuffer-PanelSend.height then
        newheight:=PanelLeftBar.height-barbuffer-PanelSend.height;
      PanelScroll.height:=newheight;
      LEDScrollback.height:=newheight;
      UpdateScrollbackLabels;
      exit;
    end;
    key:=0;
    if shift = [ssctrl] then begin
      ScrollDown(1);
      exit;
    end;
    if not EditHistory.visible then begin
      DownHistory;
      exit;
    end;
    if HistorySearch <> '' then begin
      SearchHistory('forward');
      exit;
    end;
    inc(HistoryI);
    if HistoryI >= (History.count) then begin
      HistoryI:=History.count;
      EditSend.text:='';
      TimerHistoryTimer(Sender);
      exit;
    end;
    RetrieveHistory;
    exit;
  end;
  if key = vk_Scroll then begin
    if PanelScroll.height > 0 then BtnCloseScrollback.click
    else MenuDoScrollbackClick(sender);
    key:=0;
    exit;
  end;
  if ActiveControl <> EditSend then exit;
  if shift = [ssalt] then exit;
  isnumpad:=false;
  if shift = [ssctrl] then controlling:=true;
  if key = vk_numpad0 then begin
    EditSend.readonly:=true;
    DoMacro('Numpad0',0,false);
    EditSend.readonly:=false;
    isnumpad:=true;
  end
  else if key = vk_numpad1 then begin
    EditSend.readonly:=true;
    DoMacro('Numpad1',0,false);
    EditSend.readonly:=false;
    isnumpad:=true;
  end
  else if key = vk_numpad2 then begin
    EditSend.readonly:=true;
    DoMacro('Numpad2',0,false);
    EditSend.readonly:=false;
    isnumpad:=true;
  end
  else if key = vk_numpad3 then begin
    EditSend.readonly:=true;
    DoMacro('Numpad3',0,false);
    EditSend.readonly:=false;
    isnumpad:=true;
  end
  else if key = vk_numpad4  then begin
    EditSend.readonly:=true;
    DoMacro('Numpad4',0,false);
    EditSend.readonly:=false;
    isnumpad:=true;
  end
  else if key = vk_numpad5 then begin
    EditSend.readonly:=true;
    DoMacro('Numpad5',0,false);
    EditSend.readonly:=false;
    isnumpad:=true;
  end
  else if key = vk_numpad6 then begin
    EditSend.readonly:=true;
    DoMacro('Numpad6',0,false);
    EditSend.readonly:=false;
    isnumpad:=true;
  end
  else if key = vk_numpad7 then begin
    EditSend.readonly:=true;
    DoMacro('Numpad7',0,false);
    EditSend.readonly:=false;
    isnumpad:=true;
  end
  else if key = vk_numpad8 then begin
    EditSend.readonly:=true;
    DoMacro('Numpad8',0,false);
    EditSend.readonly:=false;
    isnumpad:=true;
  end
  else if key = vk_numpad9 then begin
    EditSend.readonly:=true;
    DoMacro('Numpad9',0,false);
    EditSend.readonly:=false;
    isnumpad:=true;
  end
  else if key = vk_Decimal then begin
    EditSend.readonly:=true;
    DoMacro('NumpadD',0,false);
    EditSend.readonly:=false;
    isnumpad:=true;
  end
  else if key = vk_Divide then begin
    EditSend.readonly:=true;
    DoMacro('Numpad/',0,false);
    EditSend.readonly:=false;
    isnumpad:=true;
  end
  else if key = vk_Multiply then begin
    EditSend.readonly:=true;
    DoMacro('Numpad*',0,false);
    EditSend.readonly:=false;
    isnumpad:=true;
  end
  else if key = vk_Subtract then begin
    EditSend.readonly:=true;
    DoMacro('Numpad-',0,false);
    EditSend.readonly:=false;
    isnumpad:=true;
  end
  else if key = vk_Add then begin
    EditSend.readonly:=true;
    DoMacro('Numpad+',0,false);
    EditSend.readonly:=false;
    isnumpad:=true;
  end;
  controlling:=false;
  if isnumpad then begin
    EditSend.readonly:=true;
    isnumpad:=true;
  end;
end;

procedure TFormMain.FormKeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  EditSend.readonly:=false;
  if isnumpad then begin
    if Datawell.TableOptions3.fieldbyname('L53').asboolean then EditSend.text:='';
    isnumpad:=false;
  end;
end;

procedure TFormMain.TimerBannerTimer(Sender: TObject);
begin
  LabelMessage.left:=LabelMessage.left-2;
  if LabelMessage.left < (8-LabelMessage.width) then begin
    LabelMessage.left:=PanelAnnounce.width-22;
    inc(adcycled);
    if (adcycled >= adcycledmax) and (not BtnCloseMessage.visible) then begin
      BtnCloseMessage.show;
      ImageRegister.hide;
    end;
  end;
end;

procedure TFormMain.UpdateBasebar;
var h, messtop, tooltop, statustop: integer;
begin
// Show Record menu item
  MenuRecord.enabled:=MenuShowToolbar.checked;
// Show bars
  PanelMessageBase.visible:=Datawell.Mess;
  PanelToolbar.visible:=MenuShowToolbar.checked;
  PanelStatusbar.visible:=MenuShowStatusbar.checked;
// figure height of Basebar
  h:=0;
  if Datawell.Mess then inc(h,PanelMessageBase.height);
  if MenuShowToolbar.checked then inc(h,PanelToolbar.height);
  if MenuShowStatusbar.checked then inc(h,PanelStatusbar.height);
  PanelBasebar.height:=h;
// Place/size PanelMessage and PanelToolbar
  // widths
  PanelMessageBase.width:=PanelBasebar.width;
  PanelToolbar.width:=PanelBasebar.width;
  // tops
  messtop:=0; tooltop:=0; statustop:=0;
  if Datawell.Mess then begin
    inc(tooltop,PanelMessageBase.height);
    inc(Statustop,PanelMessageBase.height);
  end;
  if MenuShowToolbar.checked then inc(Statustop,PanelToolbar.height);
  PanelMessageBase.top:=messtop;
  PanelToolbar.top:=tooltop;
  PanelStatusbar.top:=statustop;
  PanelSends.top:=statustop+18;
//Reposition Scrollbar if necessary
  if PanelScroll.height > PanelLeftBar.height-barbuffer-PanelSend.height then begin
    PanelScroll.height:=PanelLeftBar.height-barbuffer-PanelSend.height;
    Datawell.TableOptions.edit;
    Datawell.TableOptions.fieldbyname('ScrollPosition').asinteger:=PanelScroll.height;
    Datawell.TableOptions.post;
    LEDScrollback.height:=PanelScroll.height;
  end;
end;

procedure TFormMain.EditAliasClick(Sender: TObject);
begin
  if visible then EditSend.setfocus;
end;

procedure TFormMain.m1Click(Sender: TObject);
begin
  case (sender as TSpeedButton).tag of
    1 : ParseMain(Datawell.TableOptions3.fieldbyname('Tool1').asstring,1);
    2 : ParseMain(Datawell.TableOptions3.fieldbyname('Tool2').asstring,1);
    3 : ParseMain(Datawell.TableOptions3.fieldbyname('Tool3').asstring,1);
    4 : ParseMain(Datawell.TableOptions3.fieldbyname('Tool4').asstring,1);
    5 : ParseMain(Datawell.TableOptions3.fieldbyname('Tool5').asstring,1);
    6 : ParseMain(Datawell.TableOptions3.fieldbyname('Tool6').asstring,1);
    7 : ParseMain(Datawell.TableOptions3.fieldbyname('Tool7').asstring,1);
    8 : ParseMain(Datawell.TableOptions3.fieldbyname('Tool8').asstring,1);
    9 : ParseMain(Datawell.TableOptions3.fieldbyname('Tool9').asstring,1);
   10 : ParseMain(Datawell.TableOptions3.fieldbyname('Tool10').asstring,1);
   11 : ParseMain(Datawell.TableOptions3.fieldbyname('Tool11').asstring,1);
   12 : ParseMain(Datawell.TableOptions3.fieldbyname('Tool12').asstring,1);
  end;
end;

procedure TFormMain.ShowMenu(arg: boolean);
begin
  MenuFile.visible:=arg;
  MenuEdit.visible:=arg;
  MenuScrollback.visible:=arg;
  MenuActions.visible:=arg;
  MenuGroups.visible:=arg;
  MenuAutotyper.visible:=arg;
  MenuOptions.visible:=arg;
  MenuWindow.visible:=arg;
  MenuMusic.visible:=arg;
  MenuHelp.visible:=arg;
end;

procedure TFormMain.MenuShowToolbarClick(Sender: TObject);
begin
  TMenuItem(sender).checked:=not TMenuItem(sender).checked;
  UpdateBasebar;
  FormResize(sender);
end;

procedure TFormMain.SpecialMessage(data: string);
begin
  adcycled:=0;
  LabelMessage.cursor:=Datawell.handpoint;
  PanelAnnounce.cursor:=Datawell.handpoint;
  LabelMessage.left:=PanelAnnounce.width-22;
  TimerBanner.enabled:=false;
  if data = '' then Datawell.Mess:=false
  else begin
    Datawell.Mess:=true;
    TimerBanner.enabled:=true;
  end;
  LabelMessage.caption:=data+'          ';
  UpdateBasebar;
  FormResize(nil);
  if visible then EditSend.setfocus;
end;

procedure TFormMain.MenuClearFilteredTextClick(Sender: TObject);
begin
  Datawell.ClearFiltered;
  UpdateFilteredCount;
  SystemText('System messages cleared',0);
end;

procedure TFormMain.MenuDisconnectClick(Sender: TObject);
begin
  if not Datawell.connected then begin
    messagedlg('Not connected to server',mtinformation,[mbok],0);
    exit;
  end;
  if (Datawell.TableOptions3.fieldbyname('L45').asboolean and Datawell.connected2) then Telnet2.close;
  Telnet.close;
end;

procedure TFormMain.UpdateConnection(conn: integer; status: boolean);
begin
  case conn of
    1: begin
         Datawell.connected:=status;
         BtnDisconnect.enabled:=status;
         if status then begin
           LEDConnected.bringtofront;
           PopupDisconnect.enabled:=true;
         end
         else begin
           LEDDisconnected.bringtofront;
           PopupDisconnect.enabled:=false;
         end;
       end;
  end;
end;

procedure TFormMain.MenuClearKeyhistoryClick(Sender: TObject);
begin
  History.clear;
  HistoryI:=0;
  ClearHistoryVars;
  systemText('Keyhistory cleared',0);
end;

procedure TFormMain.MUDAnsiClick(Sender: TObject);
begin
  if visible then EditSend.setfocus;
end;

procedure TFormMain.MUDAnsiBeep(Sender: TObject);
begin
  PlaySound(Datawell.TableOptions.fieldbyname('Beep').asstring,1,1,0,
    Datawell.TableOptions3.fieldbyname('L51').asboolean);
end;

procedure TFormMain.MenuCaptureScrollbackClick(Sender: TObject);
var
  F: TextFile;
  i: integer;
begin
  DialogSave.initialdir:=Datawell.GetDir(4);
  if not DialogSave.execute then exit;
  Datawell.SetDir(4,DialogSave.filename);
  AssignFile(F,DialogSave.filename);
  Rewrite(F);
  for i:=0 to MUDAnsi.lines.count-1 do begin
    WriteLn(F,MUDAnsi.lines[i]);
  end;
  CloseFile(F);
end;

procedure TFormMain.UpdateSendbar;
var h, hp2top, hp3top, hp4top: integer;
begin
  PanelHP1Bar.height:=21;
  PanelHP2Bar.height:=21;
  PanelHP3Bar.height:=20;
  PanelHP4Bar.height:=22;
// Show bars
  PanelHP1Bar.visible:=MenuShowHPBar.checked;
  PanelHP2Bar.visible:=MenuShowHP2Bar.checked;
  PanelHP3Bar.visible:=MenuShowHP3Bar.checked;
  PanelHP4Bar.visible:=MenuShowHP4Bar.checked;
// Figure height of PanelBars
  h:=0;
  if MenuShowHPBar.checked then inc(h,PanelHP1Bar.height);
  if MenuShowHP2Bar.checked then inc(h,PanelHP2Bar.height);
  if MenuShowHP3Bar.checked then inc(h,PanelHP3Bar.height);
  if MenuShowHP4Bar.checked then inc(h,PanelHP4Bar.height);
  PanelBars.height:=h;
// Place/size Panels
  PanelHP1Bar.width:=PanelBars.width;
  PanelHP2Bar.width:=PanelBars.width;
  PanelHP3Bar.width:=PanelBars.width;
  PanelHP4Bar.width:=PanelBars.width;
  PanelHP1Bar.top:=0;
  LabelEName.width:=PanelBars.width-577;
  LabelEName2.width:=LabelEName.width;
  hp2top:=0; hp3top:=0; hp4top:=0;
  if MenuShowHPBar.checked then begin
    inc(hp2top,PanelHP1Bar.height);
    inc(hp3top,PanelHP1Bar.height);
    inc(hp4top,PanelHP1Bar.height);
  end;
  PanelHP2Bar.top:=hp2top;
  if MenuShowHP2Bar.checked then begin
    inc(hp3top,PanelHP2Bar.height);
    inc(hp4top,PanelHP2Bar.height);
  end;
  PanelHP3Bar.top:=hp3top;
  if MenuShowHP3Bar.checked then begin
    inc(hp4top,PanelHP2Bar.height);
  end;
  PanelHP4Bar.top:=hp4top;
//Resize the HPBars
  UpdateHP4Bar;
end;

procedure TFormMain.MenuSetupGroupsClick(Sender: TObject);
var form: TFormGroups;
begin
  form:=TFormGroups.create(self);
  form.showmodal;
  form.free;
  SetupEvents;
end;

procedure TFormMain.PanicClose;
begin
  panicclosing:=true;
end;

procedure TFormMain.MenuPasteCommandLineClick(Sender: TObject);
var sels, sell: integer;
begin
  if Datawell.TableOptions3.fieldbyname('L53').asboolean then begin
    sels:=EditSend.selstart;
    sell:=EditSend.sellength;
    if (sels = 0) and (sell > 1) and (not homed) then begin
      EditSend.selstart:=sell;
      EditSend.sellength:=9999;
    end;
  end;
  EditSend.pastefromclipboard;
end;

procedure TFormMain.MenuCutCommandLineClick(Sender: TObject);
begin
  EditSend.cuttoclipboard;
end;

procedure TFormMain.MenuSetupDisplayColorsClick(Sender: TObject);
var
  form: TFormColors;
  h: integer;
begin
  form:=TFormColors.create(self);
  form.showmodal;
  form.free;
  UpdateColors;
  MUDAnsi.font.name:=Datawell.TableOptions.fieldbyname('FontName').asstring;
  h:=Datawell.TableOptions.fieldbyname('FontStyle').asinteger;
  MUDAnsi.font.style:=[];
  case h of
    0: MUDAnsi.font.style:=[];
    1: MUDAnsi.font.style:=[fsbold];
    2: MUDAnsi.font.style:=[fsitalic];
    3: MUDAnsi.font.style:=[fsbold, fsitalic];
  end;
  UpdateFonts;
  UpdateSendbar;
end;

procedure TFormMain.UpdateColors;
begin
  with MUDAnsi do begin
    color:=Datawell.TableOptions.fieldbyname('ColorScreen').asinteger;
    textcolor:=Datawell.TableOptions.fieldbyname('ColorText').asinteger;
    colorArray[0]:=Datawell.TableOptions.fieldbyname('Color0').asinteger;
    colorArray[1]:=Datawell.TableOptions.fieldbyname('Color1').asinteger;
    colorArray[2]:=Datawell.TableOptions.fieldbyname('Color2').asinteger;
    colorArray[3]:=Datawell.TableOptions.fieldbyname('Color3').asinteger;
    colorArray[4]:=Datawell.TableOptions.fieldbyname('Color4').asinteger;
    colorArray[5]:=Datawell.TableOptions.fieldbyname('Color5').asinteger;
    colorArray[6]:=Datawell.TableOptions.fieldbyname('Color6').asinteger;
    colorArray[7]:=Datawell.TableOptions.fieldbyname('Color7').asinteger;
    colorArray[8]:=Datawell.TableOptions.fieldbyname('Color8').asinteger;
    colorArray[9]:=Datawell.TableOptions.fieldbyname('Color9').asinteger;
    colorArray[10]:=Datawell.TableOptions.fieldbyname('Color10').asinteger;
    colorArray[11]:=Datawell.TableOptions.fieldbyname('Color11').asinteger;
    colorArray[12]:=Datawell.TableOptions.fieldbyname('Color12').asinteger;
    colorArray[13]:=Datawell.TableOptions.fieldbyname('Color13').asinteger;
    colorArray[14]:=Datawell.TableOptions.fieldbyname('Color14').asinteger;
    colorArray[15]:=Datawell.TableOptions.fieldbyname('Color15').asinteger;
    repaint;
  end;
  with Scrollback do begin
    color:=Datawell.TableOptions.fieldbyname('ColorScreen').asinteger;
    textcolor:=Datawell.TableOptions.fieldbyname('ColorText').asinteger;
    colorArray[0]:=Datawell.TableOptions.fieldbyname('Color0').asinteger;
    colorArray[1]:=Datawell.TableOptions.fieldbyname('Color1').asinteger;
    colorArray[2]:=Datawell.TableOptions.fieldbyname('Color2').asinteger;
    colorArray[3]:=Datawell.TableOptions.fieldbyname('Color3').asinteger;
    colorArray[4]:=Datawell.TableOptions.fieldbyname('Color4').asinteger;
    colorArray[5]:=Datawell.TableOptions.fieldbyname('Color5').asinteger;
    colorArray[6]:=Datawell.TableOptions.fieldbyname('Color6').asinteger;
    colorArray[7]:=Datawell.TableOptions.fieldbyname('Color7').asinteger;
    colorArray[8]:=Datawell.TableOptions.fieldbyname('Color8').asinteger;
    colorArray[9]:=Datawell.TableOptions.fieldbyname('Color9').asinteger;
    colorArray[10]:=Datawell.TableOptions.fieldbyname('Color10').asinteger;
    colorArray[11]:=Datawell.TableOptions.fieldbyname('Color11').asinteger;
    colorArray[12]:=Datawell.TableOptions.fieldbyname('Color12').asinteger;
    colorArray[13]:=Datawell.TableOptions.fieldbyname('Color13').asinteger;
    colorArray[14]:=Datawell.TableOptions.fieldbyname('Color14').asinteger;
    colorArray[15]:=Datawell.TableOptions.fieldbyname('Color15').asinteger;
    repaint;
  end;
  with EditSend do begin
    color:=Datawell.TableOptions.fieldbyname('ColorScreen').asinteger;
    font.color:=Datawell.TableOptions.fieldbyname('ColorText').asinteger;
  end;
  PanelLeftMUDAnsi.color:=Datawell.TableOptions.fieldbyname('ColorScreen').asinteger;
  PanelLeftScrollback.color:=Datawell.TableOptions.fieldbyname('ColorScreen').asinteger;
  PanelScroll.color:=Datawell.TableOptions.fieldbyname('ColorScreen').asinteger;
  PanelMain.color:=Datawell.TableOptions.fieldbyname('ColorScreen').asinteger;
  PanelBars.color:=Datawell.TableOptions.fieldbyname('ColorScreen').asinteger;
  color:=Datawell.TableOptions.fieldbyname('ColorScreen').asinteger;
end;

procedure TFormMain.MenuLogToFileClick(Sender: TObject);
var
  F: TextFile;
  work: string;
begin
  if MenuLogToFile.checked then begin
    MenuLogToFile.checked:=false;
    UpdateLogger;
    AssignFile(F,DialogSave.filename);
    Rewrite(F);
    WriteLn(F,'Log file ended: '+timetostr(time)+'  '+datetostr(date));
    WriteLn(F,'');
    CloseFile(F);
    exit;
  end;
  DialogSave.initialdir:=Datawell.GetDir(4);
  if not DialogSave.execute then exit;
  Datawell.SetDir(4,DialogSave.filename);
  work:=DialogSave.filename;
  while (length(work) > 0) and (work[length(work)] <> '\') do delete(work,length(work),1);
  MenuLogToFile.checked:=true;
  AssignFile(F,DialogSave.filename);
  Rewrite(F);
  WriteLn(F,'Log file started: '+timetostr(time)+'  '+datetostr(date));
  WriteLn(F,'');
  CloseFile(F);
  UpdateLogger;
end;

procedure TFormMain.UpdateLogger;
begin
  if MenuLogToFile.checked then begin
    LEDLogOn.hint:='Logging text to: '+DialogSave.filename+' (click to stop logging)';
    LEDLogOn.bringtofront;
  end
  else begin
    LEDLogOn.hint:='Logging text (click to stop logging)';
    LEDLogOff.bringtofront;
  end;
  PopupLogIncoming.checked:=MenuLogToFile.checked;
end;

procedure TFormMain.MUDAnsiLineCompleted(str: string; ob: TObject);
begin
  LogData;
  AddParsing;
end;

procedure TFormMain.LogData;
var F: TextFile;
begin
  if not MenuLogToFile.checked then exit;
  AssignFile(F,DialogSave.filename);
  Append(F);
  WriteLn(F,MUDAnsi.flines[MUDAnsi.flines.count-2]);
  CloseFile(F);
end;

procedure TFormMain.MenuAnchorClick(Sender: TObject);
begin
  TMenuItem(sender).checked:=not TMenuItem(sender).checked;
  UpdateWindowCaptions;
end;

procedure TFormMain.WMEnterSizeMove;
begin
  StoreAnchors;
end;

procedure TFormMain.StoreAnchors;
begin
  if not Datawell.AllCreated then exit;
  if screens[0] then begin
    AnchorTops[0]:=screenChat.top-top-height;
    AnchorLefts[0]:=screenChat.left-left-width;
  end
  else begin
    AnchorTops[0]:=Datawell.TableOptions.fieldbyname('ChatTop').asinteger-top-height;
    AnchorLefts[0]:=Datawell.TableOptions.fieldbyname('ChatLeft').asinteger-left-width;
  end;
  if screens[1] then begin
    AnchorTops[1]:=screenTell.top-top-height;
    AnchorLefts[1]:=screenTell.left-left-width;
  end
  else begin
    AnchorTops[1]:=Datawell.TableOptions.fieldbyname('TellTop').asinteger-top-height;
    AnchorLefts[1]:=Datawell.TableOptions.fieldbyname('TellLeft').asinteger-left-width;
  end;
  if screens[2] then begin
    AnchorTops[2]:=screenRoom.top-top-height;
    AnchorLefts[2]:=screenRoom.left-left-width;
  end
  else begin
    AnchorTops[2]:=Datawell.TableOptions3.fieldbyname('I31').asinteger-top-height;
    AnchorLefts[2]:=Datawell.TableOptions3.fieldbyname('I30').asinteger-left-width;
  end;
  if screens[4] then begin
    AnchorTops[4]:=screenImagery.top-top-height;
    AnchorLefts[4]:=screenImagery.left-left-width;
  end
  else begin
    AnchorTops[4]:=Datawell.TableOptions.fieldbyname('ImageryTop').asinteger-top-height;
    AnchorLefts[4]:=Datawell.TableOptions.fieldbyname('ImageryLeft').asinteger-left-width;
  end;
  if screens[6] then begin
    AnchorTops[6]:=screenFiltered.top-top-height;
    AnchorLefts[6]:=screenFiltered.left-left-width;
  end
  else begin
    AnchorTops[6]:=Datawell.TableOptions.fieldbyname('FilteredTop').asinteger-top-height;
    AnchorLefts[6]:=Datawell.TableOptions.fieldbyname('FilteredLeft').asinteger-left-width;
  end;
  AnchorTops[8]:=FormMap.top-top-height;
  AnchorLefts[8]:=FormMap.left-left-width;
  if screens[10] then begin
    AnchorTops[12]:=screenCanvas.top-top-height;
    AnchorLefts[12]:=screenCanvas.left-left-width;
  end
  else begin
    AnchorTops[12]:=Datawell.TableOptions3.fieldbyname('I12').asinteger-top-height;
    AnchorLefts[12]:=Datawell.TableOptions3.fieldbyname('I13').asinteger-left-width;
  end;
end;

procedure TFormMain.UpdateAnchors;
begin
  if not Datawell.AllCreated then exit;
  if MenuAnchor.checked then begin
    if screens[0] then begin
      screenChat.top:=top+height+AnchorTops[0];
      screenChat.left:=left+width+AnchorLefts[0];
    end
    else begin
      Datawell.TableOptions.edit;
      Datawell.TableOptions.fieldbyname('ChatTop').asinteger:=top+height+AnchorTops[0];
      Datawell.TableOptions.fieldbyname('ChatLeft').asinteger:=left+width+AnchorLefts[0];
      Datawell.TableOptions.post;
    end;
  end;
  if MenuAnchorTell.checked then begin
    if screens[1] then begin
      screenTell.top:=top+height+AnchorTops[1];
      screenTell.left:=left+width+AnchorLefts[1];
    end
    else begin
      Datawell.TableOptions.edit;
      Datawell.TableOptions.fieldbyname('TellTop').asinteger:=top+height+AnchorTops[1];
      Datawell.TableOptions.fieldbyname('TellLeft').asinteger:=left+width+AnchorLefts[1];
      Datawell.TableOptions.post;
    end;
  end;
  if MenuAnchorRoom.checked then begin
    if screens[2] then begin
      screenRoom.top:=top+height+AnchorTops[2];
      screenRoom.left:=left+width+AnchorLefts[2];
    end
    else begin
      Datawell.TableOptions3.edit;
      Datawell.TableOptions3.fieldbyname('I31').asinteger:=top+height+AnchorTops[2];
      Datawell.TableOptions3.fieldbyname('I30').asinteger:=left+width+AnchorLefts[2];
      Datawell.TableOptions3.post;
    end;
  end;
  if MenuAnchorImagery.checked then begin
    if screens[4] then begin
      screenImagery.top:=top+height+AnchorTops[4];
      screenImagery.left:=left+width+AnchorLefts[4];
    end
    else begin
      Datawell.TableOptions.edit;
      Datawell.TableOptions.fieldbyname('ImageryTop').asinteger:=top+height+AnchorTops[4];
      Datawell.TableOptions.fieldbyname('ImageryLeft').asinteger:=left+width+AnchorLefts[4];
      Datawell.TableOptions.post;
    end;
  end;
  if MenuAnchorFiltered.checked then begin
    if screens[6] then begin
      screenFiltered.top:=top+height+AnchorTops[6];
      screenFiltered.left:=left+width+AnchorLefts[6];
    end
    else begin
      Datawell.TableOptions.edit;
      Datawell.TableOptions.fieldbyname('FilteredTop').asinteger:=top+height+AnchorTops[6];
      Datawell.TableOptions.fieldbyname('FilteredLeft').asinteger:=left+width+AnchorLefts[6];
      Datawell.TableOptions.post;
    end;
  end;
  if MenuAnchorMap.checked then begin
    FormMap.top:=top+height+AnchorTops[8];
    FormMap.left:=left+width+AnchorLefts[8];
  end;
  if MenuAnchorCanvas.checked then begin
    if screens[10] then begin
      screenCanvas.top:=top+height+AnchorTops[12];
      screenCanvas.left:=left+width+AnchorLefts[12];
    end
    else begin
      Datawell.TableOptions3.edit;
      Datawell.TableOptions3.fieldbyname('I12').asinteger:=top+height+AnchorTops[12];
      Datawell.TableOptions3.fieldbyname('I13').asinteger:=left+width+AnchorLefts[12];
      Datawell.TableOptions3.post;
    end;
  end;
end;

procedure TFormMain.WMMoving;
begin
  UpdateAnchors;
end;

procedure TFormMain.WMExitSizeMove;
begin
  UpdateAnchors;
end;

procedure TFormMain.LEDLogOnClick(Sender: TObject);
begin
  MenuLogToFile.click;
end;

procedure TFormMain.UpdateWindowCaptions;
var cap: string;
begin
  if screens[0] then begin
    cap:='Chat Monitor';
    if MenuAnchor.checked then cap:='['+cap+']';
    cap:=cap+' - '+Datawell.player;
    screenChat.caption:=cap;
  end;
  if screens[1] then begin
    cap:='Tell Monitor';
    if MenuAnchorTell.checked then cap:='['+cap+']';
    cap:=cap+' - '+Datawell.player;
    screenTell.caption:=cap;
  end;
  if screens[2] then begin
    cap:='Room Monitor';
    screenRoom.caption:=cap;
  end;
  if screens[4] then begin
    cap:='Imagery';
    if MenuAnchorImagery.checked then cap:='['+cap+']';
    cap:=cap+' - '+Datawell.player;
    screenImagery.caption:=cap;
  end;
  if screens[6] then begin
    cap:='System Messages';
    if MenuAnchorFiltered.checked then cap:='['+cap+']';
    cap:=cap+' - '+Datawell.player;
    screenFiltered.caption:=cap;
  end;
  if screens[10] then begin
    cap:=Datawell.TableOptions3.fieldbyname('S31').asstring;
    if cap = '' then cap:='Canvas';
    if MenuAnchorCanvas.checked then cap:='['+cap+']';
    screenCanvas.caption:=cap;
  end;
end;

procedure TFormMain.CheckRetain;
var
  work, work2: string;
  Rspace, didfind: boolean;
begin
  if Datawell.TableOptions.fieldbyname('RetainAll').asboolean then begin
    EditSend.selectall;
    exit;
  end;
  work2:='';
  Rspace:=false;
  if not Datawell.TableOptions.fieldbyname('FRetain').asboolean then begin
    EditSend.text:='';
    exit;
  end;
  work:=EditSend.text;
  didfind := false;
  with Datawell.TableRetain do begin
    first;
    while (not EOF) do begin
      if (fieldbyname('FRetain').asstring+' ' =
        copy(work,1,length(fieldbyname('FRetain').asstring)+1)) or
        (fieldbyname('FRetain').asstring = work) then begin
          didfind:=true;
          if length(fieldbyname('FRetain').asstring) > length(work2) then begin
            work2:=fieldbyname('FRetain').asstring;
            Rspace:=fieldbyname('AddSpace').asboolean;
          end;
        end;
      next;
    end;
  end;
  if didfind then begin
    if Rspace then work2:=work2+' ';
    EditSend.text:=work2;
    EditSend.selstart:=length(EditSend.text);
    EditSend.sellength:=0;
    if not Rspace then EditSend.selectall;
  end
  else EditSend.text:='';
  if visible then EditSend.setfocus;
end;

procedure TFormMain.MenuAnchorAllClick(Sender: TObject);
begin
  if TMenuItem(sender).tag = 0 then begin
    if not MenuAnchor.checked then MenuAnchor.click;
    if not MenuAnchorTell.checked then MenuAnchorTell.click;
    if not MenuAnchorImagery.checked then MenuAnchorImagery.click;
    if not MenuAnchorFiltered.checked then MenuAnchorFiltered.click;
    if not MenuAnchorMap.checked then MenuAnchorMap.click;
    if not MenuAnchorCanvas.checked then MenuAnchorCanvas.click;
  end
  else begin
    if MenuAnchor.checked then MenuAnchor.click;
    if MenuAnchorTell.checked then MenuAnchorTell.click;
    if MenuAnchorImagery.checked then MenuAnchorImagery.click;
    if MenuAnchorFiltered.checked then MenuAnchorFiltered.click;
    if MenuAnchorMap.checked then MenuAnchorMap.click;
    if MenuAnchorCanvas.checked then MenuAnchorCanvas.click;
  end;
end;

procedure TFormMain.MenuActivateBASEClick(Sender: TObject);
begin
  Datawell.TableOptions.edit;
  Datawell.TableOptions.fieldbyname('FGroup').asstring:='BASE';
  Datawell.TableOptions.post;
  Datawell.TableOptions2.edit;
  Datawell.TableOptions2.fieldbyname('Groups').asstring:='BASE';
  Datawell.TableOptions2.post;
  SystemText('Active Text and Status Group changed to: BASE',0);
end;

procedure TFormMain.MenuInsertEscCharClick(Sender: TObject);
begin
  MemoPaste.lines.clear;
  MemoPaste.pastefromclipboard;
  EditEsc.selectall;
  EditEsc.copytoclipboard;
  EditSend.pastefromclipboard;
  MemoPaste.selectall;
  MemoPaste.copytoclipboard;
end;

procedure TFormMain.DownHistory;
var
  i, x: integer;
  work: string;
begin
  if (not ListHistory.visible) and (History.count < 1) then exit;
  with ListHistory do begin
    if not visible then begin
      x:=History.count;
      work:=EditSend.text;
      if work = '' then begin
        for i:=x-1 downto 0 do begin
          items.add(History[i]);
          ListHistoryIndex.items.add('-'+inttostr(x-i));
        end;
        color:=clwhite;
        itemindex:=0;
        ListHistoryIndex.itemindex:=0;
      end
      else begin
        for i:=x-1 downto 0 do begin
          if copy(History[i],1,length(work)) = work then begin
            items.add(History[i]);
            ListHistoryIndex.items.add('-'+inttostr(x-i));
          end;
        end;
        if items.count < 1 then begin
          items.add('No matches found');
          color:=clyellow;
        end
        else begin
          color:=claqua;
          itemindex:=0;
          ListHistoryIndex.itemindex:=0;
        end;
        EditSearch.text:='Searching on: '+work;
        EditSearch.show;
      end;
      ListHistoryIndex.show;
      show;
    end
    else begin
      if itemindex >= items.count-1 then exit;
      if itemindex < 0 then exit;
      itemindex:=itemindex+1;
      ListHistoryIndex.itemindex:=ListHistoryIndex.itemindex+1;
    end;
    bypass:=true;
    if (itemindex >= 0) and (color <> clyellow) then EditSend.text:=items[itemindex];
    if Datawell.TableOptions.fieldbyname('HighlightKeyhistory').asboolean then EditSend.selectall
    else EditSend.selstart:=length(EditSend.text);
    bypass:=false;
  end;
  TimerHistory2.enabled:=false;
  TimerHistory2.enabled:=true;
end;

procedure TFormMain.UpHistory;
begin
  with ListHistory do begin
    if itemindex <= 0 then exit;
    itemindex:=itemindex-1;
    ListHistoryIndex.itemindex:=ListHistoryIndex.itemindex-1;
    bypass:=true;
    EditSend.text:=items[itemindex];
    if Datawell.TableOptions.fieldbyname('HighlightKeyhistory').asboolean then EditSend.selectall
    else EditSend.selstart:=length(EditSend.text);
    bypass:=false;
  end;
  TimerHistory2.enabled:=false;
  TimerHistory2.enabled:=true;
end;

procedure TFormMain.CloseHistory;
begin
  if not ListHistory.visible then exit;
  ListHistory.hide;
  ListHistoryIndex.hide;
  ListHistory.items.clear;
  ListHistoryIndex.items.clear;
  ListHistory.color:=clwhite;
  EditSearch.hide;
  if visible then EditSend.setfocus;
  TimerHistory2.enabled:=false;
end;

procedure TFormMain.ListHistoryIndexClick(Sender: TObject);
begin
  if visible then EditSend.setfocus;
end;

procedure TFormMain.BtnCloseScrollbackClick(Sender: TObject);
begin
  if PanelScroll.height < 1 then exit;
  Datawell.TableOptions.edit;
  Datawell.TableOptions.fieldbyname('ScrollPosition').asinteger:=PanelScroll.height;
  Datawell.TableOptions.post;
  PanelScroll.height:=0;
  LEDScrollback.height:=0;
end;

procedure TFormMain.MenuTickerClick(Sender: TObject);
var form: TFormTicker;
begin
  if not Datawell.CheckRinged2('Ticker') then exit;
  form:=TFormTicker.create(self);
  if Datawell.TableOptions.fieldbyname('EnableTicker').asboolean then begin
    form.BtnTicker.caption:='Disable Tic&ker';
    form.BtnTicker.font.color:=clred;
  end
  else begin
    form.BtnTicker.caption:='Enable Tic&ker';
    form.BtnTicker.font.color:=clgreen;
  end;
  form.showmodal;
  form.free;
  UpdateTickerLabel;
end;

procedure TFormMain.LabelTickerDblClick(Sender: TObject);
begin
  Datawell.TableOptions.edit;
  Datawell.TableOptions.fieldbyname('EnableTicker').asboolean:=false;
  Datawell.TableOptions.post;
  UpdateTickerLabel;
end;

procedure TFormMain.UpdateTickerLabel;
begin
  if Datawell.TableOptions.fieldbyname('EnableTicker').asboolean then begin
    BevelTicker.show;
    BevelTotal.left:=38;
    LabelTotal.left:=39;
    PanelCloseHelpBar.width:=95;
    BtnCloseHelpBar.left:=79;
  end
  else begin
    BevelTicker.hide;
    BevelTotal.left:=0;
    LabelTotal.left:=2;
    PanelCloseHelpBar.width:=57;
    BtnCloseHelpBar.left:=41;
  end;
end;

procedure TFormMain.ToggleTicker;
var
  val: boolean;
  work: string;
begin
  val:=not Datawell.TableOptions.fieldbyname('EnableTicker').asboolean;
  Datawell.TableOptions.edit;
  Datawell.TableOptions.fieldbyname('EnableTicker').asboolean:=val;
  Datawell.TableOptions.post;
  if val then begin
    work:='Enabled';
  end
  else work:='Disabled';
  Systemtext('Ticker: '+work,0);
  UpdateTickerLabel;
end;

procedure TFormMain.PopupResetTickerClick(Sender: TObject);
begin
   FTickers.Clear;
end;

procedure TFormMain.UpdateFonts;
begin
  Scrollback.font.name:=MUDAnsi.font.name;
  Scrollback.font.size:=MUDAnsi.font.size;
  Scrollback.font.style:=MUDAnsi.font.style;
  Scrollback.font.color:=Datawell.TableOptions.fieldbyname('ColorText').asinteger;
  EditSend.font.name:=MUDAnsi.font.name;
  EditSend.font.size:=MUDAnsi.font.size;
  EditSend.font.style:=MUDAnsi.font.style;
  EditSend.font.color:=Datawell.TableOptions.fieldbyname('ColorText').asinteger;
end;

procedure TFormMain.UpdateHyperlinks;
begin
  with Datawell do begin
    MUDAnsi.EnableLinks:=TableOptions2.fieldbyname('EnableHyperlinks').asboolean;
    MUDAnsi.LinkFG:=FigureColor(TableOptions2.fieldbyname('HyperlinkFGColor').asinteger);
    MUDAnsi.LinkBG:=FigureColor(TableOptions2.fieldbyname('HyperlinkBGColor').asinteger);
    Scrollback.EnableLinks:=TableOptions2.fieldbyname('EnableHyperlinks').asboolean;
    Scrollback.LinkFG:=FigureColor(TableOptions2.fieldbyname('HyperlinkFGColor').asinteger);
    Scrollback.LinkBG:=FigureColor(TableOptions2.fieldbyname('HyperlinkBGColor').asinteger);
  end;
end;

procedure TFormMain.MenuCtrlTabClick(Sender: TObject);
begin
  tabbing:=true;
  MenuOpenAutotyper.click;
  MenuShowChat.click;
  MenuShowTell.click;
  MenuShowImagery.click;
  MenuShowFiltered.click;
  MenuShowCartographer.click;
  tabbing:=false;
end;

procedure TFormMain.MenuCtrlTab2Click(Sender: TObject);
begin
  tabbing:=true;
  MenuShowCartographer.click;
  MenuShowFiltered.click;
  MenuShowImagery.click;
  MenuShowTell.click;
  MenuShowChat.click;
  MenuOpenAutotyper.click;
  tabbing:=false;
end;

procedure TFormMain.NextScreen(from: integer);
begin
  tabbing:=true;
  case from of
    1: begin
         MenuShowChat.click;
         MenuShowTell.click;
         MenuShowFiltered.click;
         MenuShowCartographer.click;
         show;
         bringtofront;
       end;
    2: begin
         MenuShowTell.click;
         MenuShowFiltered.click;
         MenuShowCartographer.click;
         show;
         bringtofront;
       end;
    3: begin
         MenuShowFiltered.click;
         MenuShowCartographer.click;
         show;
         bringtofront;
       end;
    4: begin
         MenuShowFiltered.click;
         MenuShowCartographer.click;
         show;
         bringtofront;
       end;
    5: begin
         MenuShowFiltered.click;
         MenuShowCartographer.click;
         show;
         bringtofront;
       end;
    6: begin
         MenuShowFiltered.click;
         MenuShowCartographer.click;
         show;
         bringtofront;
       end;
    7: begin
         MenuShowFiltered.click;
         MenuShowCartographer.click;
         show;
         bringtofront;
       end;
    8: begin
         MenuShowCartographer.click;
         show;
         bringtofront;
       end;
    9: begin
         MenuShowCartographer.click;
         show;
         bringtofront;
       end;
    10: begin
         MenuShowCartographer.click;
         show;
         bringtofront;
       end;
    11: begin
         MenuShowCartographer.click;
         show;
         bringtofront;
       end;
    12: begin
         MenuShowRoom.click;
         show;
         bringtofront;
       end;
    13: begin
         show;
         bringtofront;
       end;
  end;
  tabbing:=false;
end;

procedure TFormMain.PriorScreen(from: integer);
begin
  tabbing:=true;
  case from of
    1: begin
         show;
         bringtofront;
       end;
    2: begin
         MenuOpenAutotyper.click;
         show;
         bringtofront;
       end;
    3: begin
         MenuShowChat.click;
         MenuOpenAutotyper.click;
         show;
         bringtofront;
       end;
    4: begin
         MenuShowTell.click;
         MenuShowChat.click;
         MenuOpenAutotyper.click;
         show;
         bringtofront;
       end;
    5: begin
         MenuShowTell.click;
         MenuShowChat.click;
         MenuOpenAutotyper.click;
         show;
         bringtofront;
       end;
    6: begin
         MenuShowTell.click;
         MenuShowChat.click;
         MenuOpenAutotyper.click;
         show;
         bringtofront;
       end;
    7: begin
         MenuShowTell.click;
         MenuShowChat.click;
         MenuOpenAutotyper.click;
         show;
         bringtofront;
       end;
    8: begin
         MenuShowTell.click;
         MenuShowChat.click;
         MenuOpenAutotyper.click;
         show;
         bringtofront;
       end;
    9: begin
         MenuShowFiltered.click;
         MenuShowTell.click;
         MenuShowChat.click;
         MenuOpenAutotyper.click;
         show;
         bringtofront;
       end;
    10: begin
         MenuShowFiltered.click;
         MenuShowTell.click;
         MenuShowChat.click;
         MenuOpenAutotyper.click;
         show;
         bringtofront;
       end;
    11: begin
         MenuShowFiltered.click;
         MenuShowTell.click;
         MenuShowChat.click;
         MenuOpenAutotyper.click;
         show;
         bringtofront;
       end;
    12: begin
         MenuShowCartographer.click;
         MenuShowFiltered.click;
         MenuShowTell.click;
         MenuShowChat.click;
         MenuOpenAutotyper.click;
         show;
         bringtofront;
       end;
  end;
  tabbing:=false;
end;

procedure TFormMain.OpenFloater(which: integer);
begin
  case which of
      1: MenuShowChat.click;
      2: MenuShowTell.click;
      5: MenuShowImagery.click;
      7: MenuShowFiltered.click;
      9: MenuShowCartographer.click;
     13: MenuShowCanvas.click;
    999: MenuOpenAutotyper.click;
  end;
end;

procedure TFormMain.SystemText(str: string; ul: integer);
var bul: boolean;
begin
  if ul = 1 then bul:=true else bul:=false;
  MUDAnsi.InsertFormatedText(Datawell.TableOptions.fieldbyname('FColorSystem').asinteger,
    Datawell.TableOptions.fieldbyname('BColorSystem').asinteger,str+#10+#13,false,bul);
  UpdateTotalLabel;
end;

procedure TFormMain.DisableForms;
begin
  if screens[11] then screenEditor.enabled:=false;
  FormMap.enabled:=false;
  enabled:=false;
end;

procedure TFormMain.EnableForms;
begin
  if screens[11] then screenEditor.enabled:=true;
  FormMap.enabled:=true;
  enabled:=true;
end;

function TFormMain.ParseParsing(data: string; kind: integer): boolean;
var
  work, ch: string;
  i: integer;
  rev, frev, ran: boolean;
  coms: TStringList;
begin
  result:=false;
  frev:=false;
  rev:=false;
  ran:=false;
  ch:=Datawell.TableOptions.fieldbyname('Activator').asstring;
  if data = ch then begin
    result:=true;
    exit;
  end;
  i:=pos(' ',data);
  if i > 0 then begin
    if Datawell.ToIntPure(copy(data,1,i-1)) > 0 then exit;
  end;
  if copy(data,1,1) = '-' then begin
    rev:=true;
    delete(data,1,1);
  end;
  if copy(data,1,1) = '-' then begin
    frev:=true;
    delete(data,1,1);
  end;
  if copy(data,1,1) = '*' then begin
    ran:=true;
    delete(data,1,1);
  end;
  data:=Datawell.subs('~'+ch,Datawell.specialcode,data);
  data:=Datawell.subs(ch+ch,ch+' '+ch,data);
  i:=pos(ch,data);
  if i < 1 then exit;
  result:=true;
  if kind = 1 then kind:=10;
  coms:=TStringList.create;
  while (i >= 1) and (length(data) > 1) do begin
    work:=copy(data,1,i-1);
    work:=Datawell.CheckAllSpaces(work);
    work:=Datawell.subs(Datawell.specialcode,ch,work);
    coms.add(work);
    delete(data,1,i);
    i:=pos(ch,data);
  end;
  if length(data) > 0 then begin
    data:=Datawell.CheckAllSpaces(data);
    data:=Datawell.subs(Datawell.specialcode,ch,data);
    coms.add(data);
  end;
  if ran then begin
    //random
    work:=coms[random(coms.count)];
    ParseMain(work,kind);
  end
  else begin
    if rev then begin
      if frev then begin
        //full reversed
        for i:=coms.count-1 downto 0 do ParseMain(coms[i],kind);
      end
      else begin
        //reversed
        for i:=coms.count-1 downto 0 do begin
          coms[i]:=Datawell.reverse(coms[i]);
          if coms[i] <> '' then ParseMain(coms[i],kind);
        end;
      end;
    end
    else begin
      //normal
      for i:=0 to coms.count-1 do ParseMain(coms[i],kind);
    end;
  end;
  coms.free;
end;

function TFormMain.ParseGroup(data: string): boolean;
var
  work: string;
  didfind: boolean;
  i: integer;
  groups, already: TStringList;
  table: TClientDataset;
begin
  result:=false;
  data:=Datawell.Nick(data);
  data:=lowercase(data);
  if copy(data,1,1) <> 'g' then exit;
  result:=true;
  if DoDelaying(data) then exit;
  delete(data,1,1);
  if data = '' then begin
    groups:=TStringList.create;
    Datawell.explode(Datawell.TableOptions2.fieldbyname('Groups').asstring,',',groups);
    SystemText('Currently Activated Groups                           '+
      '                          ',1);
    for i:=0 to groups.count-1 do begin
      fmtstr(work,'  %-77s',[groups[i]]);
      SystemText(work,0);
    end;
    SystemText('                                                     '+
      '                          ',0);
    fmtstr(work,'Active Status Group: %-58s',[Datawell.TableOptions.fieldbyname('FGroup').asstring]);
    SystemText(work,0);
    groups.free;
    exit;
  end;
  if copy(data,1,1) <> ' ' then begin
    result:=false;
    exit;
  end;
  delete(data,1,1);
  if copy(data,1,7) = 'create ' then begin
    delete(data,1,7);
    if (pos('"',data) > 0) or (pos(',',data) > 0) then begin
      SystemText('Group names cannot contain quotes or commas',0);
      exit;
    end;
    if length(data) > 25 then begin
      SystemText('Groups cannot be longer than 25 characters',0);
      exit;
    end;
    data:=Datawell.CutTrailingSpaces(data);
    data:=uppercase(data);
    didfind:=false;
    table:=TClientDataset.create(self);
    with table do begin
      CloneCursor(Datawell.TableGroups, false);
      filtered := true;
      active:=true;
      first;
      while not EOF do begin
        if fieldbyname('FGroup').asstring = data then begin
          didfind:=true;
          break;
        end;
        next;
      end;
    end;
    if didfind then begin
      SystemText('Group '+data+' already exists',0);
      table.free;
      exit;
    end;
    with table do begin
      append;
      fieldbyname('Master').asinteger:=Datawell.masterinteger;
      fieldbyname('FGroup').asstring:=data;
      fieldbyname('FGColor').asinteger:=clblack;
      fieldbyname('BGColor').asinteger:=clwhite;
      post;
    end;
    table.free;
    SystemText('Group '+data+' created',0);
    exit;
  end;
  if copy(data,1,7) = 'status ' then begin
    delete(data,1,7);
    data:=uppercase(data);
    didfind:=false;
    table:=TClientDataset.create(self);
    with table do begin
      CloneCursor(Datawell.TableGroups, false);
      filtered := true;
      active:=true;
      first;
      while not EOF do begin
        if fieldbyname('FGroup').asstring = data then begin
          didfind:=true;
          break;
        end;
        next;
      end;
    end;
    if not didfind then begin
      SystemText('Group '+data+' does not exist',0);
      table.free;
      exit;
    end;
    if Datawell.TableOptions.fieldbyname('FGroup').asstring =
       table.fieldbyname('FGroup').asstring then begin
       SystemText('Active Status Group remains: '+Datawell.TableOptions.fieldbyname('FGroup').asstring,0);
    end
    else begin
      Datawell.TableOptions.edit;
      Datawell.TableOptions.fieldbyname('FGroup').asstring:=table.fieldbyname('FGroup').asstring;
      Datawell.TableOptions.post;
      SystemText('Active Status Group changed to: '+Datawell.TableOptions.fieldbyname('FGroup').asstring,0);
      SetupEvents;
    end;
    table.free;
    exit;
  end;
  data:=uppercase(data);
  groups:=TStringList.create;
  already:=TStringList.create;
  Datawell.explode(data,',',groups);
  if groups.indexof('BASE') < 0 then begin
    SystemText('BASE group (required) being added to active group list',0);
    groups.add('BASE');
  end;
  if groups.count >= 10 then begin
    SystemText('You can only have a maximum of 10 active groups',0);
    exit;
  end;
  work:='';
  table:=TClientDataset.create(self);
  with table do begin
    CloneCursor(Datawell.TableGroups, false);
    filtered := true;
    active:=true;
    for i:=0 to groups.count-1 do begin
      first;
      didfind:=false;
      while not EOF do begin
        if fieldbyname('FGroup').asstring = groups[i] then begin
          didfind:=true;
          break;
        end;
        next;
      end;
      if didfind then begin
        if already.indexof(groups[i]) < 0 then begin
          work:=work+','+groups[i];
          already.add(groups[i]);
        end;
      end;
    end;
  end;
  table.free;
  if copy(work,1,1) = ',' then delete(work,1,1);
  if work <> '' then begin
    if Datawell.TableOptions2.fieldbyname('Groups').asstring = work then begin
       SystemText('Active Groups remain: '+Datawell.TableOptions2.fieldbyname('Groups').asstring,0);
    end
    else begin
      Datawell.TableOptions2.edit;
      Datawell.TableOptions2.fieldbyname('Groups').asstring:=work;
      Datawell.TableOptions2.post;
      SystemText('Active Groups set to: '+work,0);
      SetupEvents;
    end;
  end
  else begin
    SystemText('No valid groups: '+data,0);
  end;
  groups.free;
  already.free;
end;

function TFormMain.ParseTicker(data: string): boolean;
var
  ttick, taction, work, work2, original: string;
  i, amt: integer;
  headershown, didfind: boolean;
  table: TClientDataset;
begin
  result:=false;
  if copy(data,1,3) = 'rt ' then begin
    original:=data;
    delete(data,1,1);
    if copy(data,1,2) <> 't ' then exit;
    delete(data,1,1);
    if copy(data,1,1) <> ' ' then exit;
    data:=Datawell.CutLeadingspaces(data);
    if data = '' then exit;
    result:=true;
    if DoDelaying(original) then exit;
    i:=pos(Datawell.TableOptions.fieldbyname('Activator').asstring,data);
    ttick:=copy(data,1,i-1);
    taction:=copy(data,i+1,9999);
    taction:=Datawell.subs('~'+Datawell.TableOptions.fieldbyname('Activator').asstring,
      Datawell.TableOptions.fieldbyname('Activator').asstring,taction);
    i:=Datawell.ToInt(ttick);
    if i < 1 then begin
      SystemText('The tick must be an integer',0);
      exit;
    end;
    if taction = '' then begin
      SystemText('Format is: '+Datawell.TableOptions.fieldbyname('Activator').asstring+
        'rt <tick>'+Datawell.TableOptions.fieldbyname('Activator').asstring+'<action>',0);
      exit;
    end;
    table:=TClientDataset.create(self);
    with table do begin
      CloneCursor(Datawell.TableTicker, false);
      filter := '(Master = '+Datawell.masterindex+') and (Tick = '+ttick+')';
      filtered := true;
      active:=true;
      first;
      didfind:=false;
      while not EOF do begin
        if fieldbyname('Action').asstring = taction then begin
          didfind:=true;
          break;
        end;
        next;
      end;
      if not didfind then begin
        SystemText('Client ticker "'+ttick+'/'+taction+'" does not exist',0);
        exit;
      end;
      delete;
    end;
    table.free;
    SystemText('Client ticker "'+ttick+'/'+taction+'" deleted',0);
    exit;
  end;
  if copy(data,1,1) <> 't' then exit;
  result:=true;
  if DoDelaying(data) then exit;
  delete(data,1,1);
  data:=NormalizeData(data);
//list tickers
  headershown:=false;
  if data = '' then begin
    SystemText('Client Tickers Defined:',0);
    table:=TClientDataset.create(self);
    with table do begin
      CloneCursor(Datawell.TableTicker, false);
      filtered := true;
      active:=true;
      first;
      amt:=0;
      while not EOF do begin
        inc(amt);
        work:=copy(inttostr(fieldbyname('Tick').asinteger),1,3);
        work2:=copy(fieldbyname('Action').asstring,1,25);
        fmtstr(work,'   %-3s  %-71s',[work,work2]);
        if not headershown then begin
          SystemText('  Tick  Action                       '+
            '                                          ',1);
          headershown:=true;
        end;
        SystemText(work,0);
        next;
      end;
    end;
    table.free;
    if amt < 1 then SystemText('  <no client tickers exist>',0);
    exit;
  end;
  if copy(data,1,1) <> ' ' then begin
    result:=false;
    exit;
  end;
  data:=Datawell.CutLeadingSpaces(data); //no leading spaces
//toggle ticker
  if (data = 'toggle') or (data = 't') then begin
    result:=true;
    ToggleTicker;
    exit;
  end;
//enable ticker
  if data = 'on' then begin
    if Datawell.TableOptions.fieldbyname('EnableTicker').asboolean then begin
      SystemText('Ticker already enabled',0);
      exit;
    end;
    Datawell.TableOptions.edit;
    Datawell.TableOptions.fieldbyname('EnableTicker').asboolean:=true;
    Datawell.TableOptions.post;
    SystemText('Ticker enabled',0);
    UpdateTickerLabel;
    exit;
  end;
//disable ticker
  if data = 'off' then begin
    if not Datawell.TableOptions.fieldbyname('EnableTicker').asboolean then begin
      SystemText('Ticker already disabled',0);
      exit;
    end;
    Datawell.TableOptions.edit;
    Datawell.TableOptions.fieldbyname('EnableTicker').asboolean:=false;
    Datawell.TableOptions.post;
    SystemText('Ticker disabled',0);
    UpdateTickerLabel;
    exit;
  end;
//reset ticker
  if (data = 'reset') or (data = 'r') then begin
    result:=true;
    PopupResetTickerClick(nil);
    SystemText('Ticker Reset',0);
    exit;
  end;
//add ticker
  i:=pos(Datawell.TableOptions.fieldbyname('Activator').asstring,data);
  if i < 1 then begin
    SystemText('Format is: '+Datawell.TableOptions.fieldbyname('Activator').asstring+
      't <tick>'+Datawell.TableOptions.fieldbyname('Activator').asstring+'<action>',0);
    exit;
  end;
  ttick:=copy(data,1,i-1);
  taction:=copy(data,i+1,9999);
  taction:=Datawell.subs(Datawell.specialcode,
    Datawell.TableOptions.fieldbyname('Activator').asstring,taction);
  i:=Datawell.ToInt(ttick);
  if i < 1 then begin
    SystemText('The tick must be an integer',0);
    exit;
  end;
  if (i < 2) or (i > 3600) then begin
    SystemText('The tick can range from 2-3600',0);
    exit;
  end;
  if taction = '' then begin
    SystemText('Format is: '+Datawell.TableOptions.fieldbyname('Activator').asstring+
      't <tick>'+Datawell.TableOptions.fieldbyname('Activator').asstring+'<action>',0);
    exit;
  end;
  if pos('"',taction) > 0 then begin
    SystemText('Ticker actions cannot contain quotes',0);
    exit;
  end;
  if length(taction) > 250 then begin
    SystemText('Ticker actions cannot be longer than 250 characters',0);
    exit;
  end;
  table:=TClientDataset.create(self);
  with table do begin
    CloneCursor(Datawell.TableTicker, false);
    Filter := '(Master = '+Datawell.masterindex+') and (Tick = '+ttick+')';
    filtered := true;
    active:=true;
    first;
    didfind:=false;
    while not EOF do begin
      if fieldbyname('Action').asstring = taction then begin
        didfind:=true;
        break;
      end;
      next;
    end;
    filter := '';
    filtered := true;
    active:=true;
    if didfind then edit
    else append;
    fieldbyname('Master').asinteger:=Datawell.masterinteger;
    fieldbyname('Tick').asinteger:=i;
    fieldbyname('Action').asstring:=taction;
    post;
  end;
  table.free;
  if didfind then SystemText('Client Ticker Replaced:',0)
  else SystemText('Client Ticker Added:',0);
  work:=copy(ttick,1,3);
  work2:=copy(taction,1,71);
  fmtstr(work,'   %-3s  %-71s',[work,work2]);
  SystemText('  Tick  Action                       '+
    '                                          ',1);
  SystemText(work,0);
end;

function TFormMain.ParsePassword(data: string): boolean;
begin
  result:=false;
  data:=lowercase(data);
  if data <> 'password' then exit;
  result:=true;
  if DoDelaying(data) then exit;
  if (Datawell.password = '') or (Datawell.password = '<NIL>') then begin
    SystemText('((PASSWORD not set))',0);
    exit;
  end;
  if (not Datawell.connected) and (not Datawell.connected2) then begin
    systemtext('Not connected to server',0);
    exit;
  end;
  if (Datawell.connected) or (Datawell.connected2) then begin
    if BtnMUD1.down then Telnet.SendStr(Datawell.password+Datawell.cr)
    else Telnet2.SendStr(Datawell.password+Datawell.cr2);
  end;
  SystemText('((PASSWORD Sent))',0);
end;

function TFormMain.ParseLastCommand(data: string; kind: integer): boolean;
var i, amt: integer;
begin
  result:=false;
  if data = '' then begin
    ParseMain(lastcommand,kind);
    result:=true;
    exit;
  end;
  if pos(' ',data) > 0 then exit;
  amt:=Datawell.ToIntPure(data);
  if amt < 1 then exit;
  result:=true;
  if amt > 99 then amt:=99;
  if FigureEcho(kind) then begin
    MUDAnsi.InsertFormatedText(FigureFColor(kind),FigureBColor(kind),
      'Repeat '+inttostr(amt)+': '+lastcommand+#10,false,false);
  end;
  for i:=1 to amt do ParseMain(lastcommand,kind);
end;

function TFormMain.ParseEvent(data: string): boolean;
var
  eevent, egroup, ch, work, work2, work3, work4, original: string;
  i, j, k, amt, highorder, kind: integer;
  didfind, didfind2, headershown, docase, dofilt, doret, doterm: boolean;
  cmds: TStringList;
  table, gtable: TClientDataset;
begin
  work:=''; work2:=''; work3:=''; work4:='';
  headershown:=false;
  result:=false;
  ch:=Datawell.TableOptions.fieldbyname('Activator').asstring;
//remove event
  if copy(data,1,3) = 're ' then begin
    original:=data;
    delete(data,1,1);
    if copy(data,1,1) <> 'e' then exit;
    delete(data,1,1);
    if copy(data,1,1) <> ' ' then exit;
    data:=Datawell.CutLeadingspaces(data);
    if data = '' then exit;
    result:=true;
    if DoDelaying(original) then exit;
    data:=Datawell.subs('"','',data);
    i:=pos(ch,data);
    if i > 0 then begin
      egroup:=copy(data,1,i-1);
      egroup:=uppercase(egroup);
      eevent:=copy(data,i+1,9999);
    end
    else begin
      eevent:=data;
      egroup:='';
    end;
    if egroup = '' then egroup:='BASE';
    if eevent = '' then begin
      SystemText('Format is: '+ch+'re <event>'+ch+'<group>',0);
      exit;
    end;
    didfind:=false;
    table:=TClientDataset.create(self);
    with table do begin
      CloneCursor(Datawell.TableEvents, false);
      filter := '(Master = '+Datawell.masterindex+') and (FGroup = '''+egroup+''')';
      filtered := true;
      active:=true;
      while not EOF do begin
        if fieldbyname('FEvent').asstring = eevent then begin
          didfind:=true;
          delete;
          break;
        end;
        next;
      end;
    end;
    table.free;
    if not didfind then begin
      SystemText('Client event "'+eevent+'" does not exist for group "'+egroup+'"',0);
      exit;
    end;
    SystemText('Client event "'+eevent+'" deleted from group "'+egroup+'"',0);
    SetupEvents;
    exit;
  end;
//disable/enable individual event
  if (copy(data,1,2) = 'de') or (copy(data,1,2) = 'ee') or (copy(data,1,2) = 'te') then begin
    original:=data;
    if copy(data,1,1) = 'd' then kind:=1
    else if copy(data,1,1) = 'e' then kind:=2
    else kind:=0;
    delete(data,1,1);
    if copy(data,1,1) <> 'e' then exit;
    delete(data,1,1);
    if data = '' then exit;
    if copy(data,1,1) <> ' ' then exit;
    data:=Datawell.CutLeadingspaces(data);
    if data = '' then exit;
    result:=true;
    if DoDelaying(original) then exit;
    data:=Datawell.subs('"','',data);
    i:=pos(ch,data);
    if i > 0 then begin
      egroup:=copy(data,1,i-1);
      egroup:=uppercase(egroup);
      eevent:=copy(data,i+1,9999);
    end
    else begin
      eevent:=data;
      egroup:='';
    end;
    if egroup = '' then egroup:='BASE';
    if eevent = '' then begin
      SystemText('Format is: '+ch+'de/ee/te <event>'+ch+'<group>',0);
      exit;
    end;
    didfind:=false;
    table:=TClientDataset.create(self);
    with table do begin
      CloneCursor(Datawell.TableEvents, false);
      filter := '(Master = '+Datawell.masterindex+') and (FGroup = '''+egroup+''')';
      filtered := true;
      active:=true;
      while not EOF do begin
        if fieldbyname('FEvent').asstring = eevent then begin
          didfind:=true;
          edit;
          work:=fieldbyname('FAction').asstring;
          case kind of
            0: if copy(work,1,1) = '|' then work:=copy(work,2,9999) else work:='|'+work;
            1: if copy(work,1,1) <> '|' then work:='|'+work;
            2: if copy(work,1,1) = '|' then work:=copy(work,2,9999);
          end;
          fieldbyname('FAction').asstring:=work;
          post;
          break;
        end;
        next;
      end;
    end;
    table.free;
    if not didfind then begin
      SystemText('Client event "'+eevent+'" does not exist for group "'+egroup+'"',0);
      exit;
    end;
    if copy(work,1,1) = '|' then work:='Disabled' else work:='Enabled';
    SystemText(work+': Event "'+eevent+'" in group "'+egroup+'"',0);
    SetupEvents;
    exit;
  end;
//list events
  if copy(data,1,1) <> 'e' then exit;
  result:=true;
  if DoDelaying(data) then exit;
  delete(data,1,1);
  data:=Datawell.subs('~'+ch,Datawell.specialcode,data);
  data:=Datawell.subs('  ',' ',data); //no double spaces
  data:=Datawell.CutTrailingSpaces(data); //no trailing spaces
  if data = '' then begin
    SystemText('Client Events Defined:',0);
    gtable:=TClientDataset.create(self);
    with gtable do begin
      CloneCursor(Datawell.TableGroups, false);
      filtered := true;
      active:=true;
      first;
      amt:=0;
      while not EOF do begin
        table:=TClientDataset.create(self);
        table.CloneCursor(Datawell.TableEvents, false);
        table.Filter := format('(Master = %s) and (FGroup = %s)',
                                [Datawell.masterindex, fieldbyname('FGroup').asstring]);
        table.filtered := true;
        table.active:=true;
        table.first;
        while not table.EOF do begin
          inc(amt);
          work2:=copy(table.fieldbyname('FGroup').asstring,1,15);
          work3:=copy(table.fieldbyname('FEvent').asstring,1,25);
          work4:=copy(table.fieldbyname('FAction').asstring,1,32);
          if copy(work4,1,1) = '|' then system.delete(work4,1,1);
          fmtstr(work,'  %-15s  %-25s  %-33s',[work2,work3,work4]);
          if not headershown then begin
            SystemText('  Group            Event                    '+
              '  Variables Used (if any)          ',1);
            headershown:=true;
          end;
          SystemText(work,0);
          table.next;
        end;
        table.free;
        next;
      end;
    end;
    if amt < 1 then SystemText('  <no client events exist>',0);
    gtable.free;
    exit;
  end;
  if copy(data,1,1) <> ' ' then begin
    result:=false;
    exit;
  end;
  data:=Datawell.CutLeadingSpaces(data); //no leading spaces
//disable/enable events
  if (data = 'disable') or (data = 'd') then begin
    if ImageDisableEvent.visible then EnableEvents(0)
    else systemtext('Events are already disabled',0);
    exit;
  end
  else if (data = 'enable') or (data = 'e') then begin
    if ImageEnableEvent.visible then EnableEvents(1)
    else systemtext('Events are already enabled',0);
    exit;
  end
  else if (data = 'toggle') or (data = 't') then begin
    if ImageEnableEvent.visible then EnableEvents(1)
    else EnableEvents(0);
    exit;
  end;
//add event
  j:=pos('~',data);
  k:=pos(ch,data);
  if k < 0 then begin
    SystemText('Format is: '+ch+'event <group>~<event>'+ch+'<a1>'+ch+
      '<a2>'+ch+'...'+ch+'<aN>',0);
    exit;
  end;
  if (j = 0) or (j > k) then begin
    egroup:='BASE';
    eevent:=copy(data,1,k-1);
  end
  else begin
    egroup:=copy(data,1,j-1);
    eevent:=copy(data,j+1,k-j-1);
  end;
  if egroup = '' then egroup:='BASE';
  egroup:=uppercase(egroup);
  if (eevent = '') or (pos(Datawell.specialcode,eevent) > 0) then begin
    SystemText('Format is: '+ch+'event <group>~<event>'+ch+'<a1>'+ch+
      '<a2>'+ch+'...'+ch+'<aN>',0);
    exit;
  end;
  didfind2:=false;
  gtable:=TClientDataset.create(self);
  with gtable do begin
    CloneCursor(Datawell.TableGroups, false);
    filtered := true;
    active:=true;
    first;
    while not EOF do begin
      if fieldbyname('FGroup').asstring = egroup then begin
        didfind2:=true;
        break;
      end;
      next;
    end;
  end;
  gtable.free;
  if not didfind2 then begin
    SystemText('Group '+egroup+' does not exist',0);
    exit;
  end;
  delete(data,1,k);
  if data = '' then begin
    SystemText('Format is: '+ch+'event <group>~<event>'+ch+'<a1>'+ch+
      '<a2>'+ch+'...'+ch+'<aN>',0);
    exit;
  end;
  if pos('"',eevent) > 0 then begin
    SystemText('Events cannot contain quotes',0);
    exit;
  end;
  if pos('*',eevent) > 0 then begin
    SystemText('To use variables withan event, you must use the Events Screen',0);
    exit;
  end;
  if length(eevent) > 60 then begin
    SystemText('Events cannot be longer than 60 characters',0);
    exit;
  end;
  amt:=0;
  highorder:=0;
  table:=TClientDataset.create(self);
  with table do begin
    CloneCursor(Datawell.TableEvents, false);
    filter := '(Master = '+Datawell.masterindex+') and (FGroup = '''+egroup+''')';
    filtered := true;
    active:=true;
    first;
    while not EOF do begin
      inc(amt);
      if fieldbyname('FOrder').asinteger > highorder then highorder:=fieldbyname('FOrder').asinteger;
      next;
    end;
  end;
  table.free;
  if amt >= 25 then begin
    SystemText('You can only have 25 events defined per group',0);
    exit;
  end;
  inc(highorder);
  //Determine switches (if any)
  // docase, dofilt, doret, doterm
  docase:=false;
  dofilt:=false;
  doret:=false;
  doterm:=false;
  work:=data;
  i:=pos('-c',lowercase(work));
  if i > 0 then begin
    docase:=true;
    work:=copy(work,1,i-1)+copy(work,i+2,9999);
  end;
  i:=pos('-f',lowercase(work));
  if i > 0 then begin
    dofilt:=true;
    work:=copy(work,1,i-1)+copy(work,i+2,9999);
  end;
  i:=pos('-r',lowercase(work));
  if i > 0 then begin
    doret:=true;
    work:=copy(work,1,i-1)+copy(work,i+2,9999);
  end;
  i:=pos('-t',lowercase(work));
  if i > 0 then begin
    doterm:=true;
    work:=copy(work,1,i-1)+copy(work,i+2,9999);
  end;
  if copy(work,length(work),1) <> ' ' then begin
    //There weren't switches, revert back
    docase:=false;
    dofilt:=false;
    doret:=false;
    doterm:=false;
  end
  else data:=Datawell.cuttrailingspaces(work);
  table:=TClientDataset.create(self);
  with table do begin
    CloneCursor(Datawell.TableEvents, false);
    filter := '(Master = '+Datawell.masterindex+') and (FGroup = '''+egroup+''')';
    filtered := true;
    active:=true;
    didfind:=false;
    while not EOF do begin
      if fieldbyname('FEvent').asstring = eevent then begin
        didfind:=true;
        break;
      end;
      next;
    end;
    if didfind then edit
    else append;
    fieldbyname('Master').asinteger:=Datawell.masterinteger;
    fieldbyname('FGroup').asstring:=egroup;
    fieldbyname('FEvent').asstring:=eevent;
    fieldbyname('FAction').asstring:='';
    fieldbyname('Sound').asstring:='';
    fieldbyname('Soundfile').asstring:='';
    fieldbyname('FColor').asinteger:=claqua;
    fieldbyname('BColor').asinteger:=clteal;
    fieldbyname('CaseSensitive').asboolean:=docase;
    fieldbyname('Terminal').asboolean:=doterm;
    fieldbyname('Filtered').asboolean:=dofilt;
    fieldbyname('FRetain').asboolean:=doret;
    if not didfind then fieldbyname('FOrder').asinteger:=highorder;
    cmds:=TStringList.create;
    Datawell.explode(data,ch,cmds);
    for i:=0 to cmds.count-1 do cmds[i]:=Datawell.subs(Datawell.specialcode,ch,cmds[i]);
    fieldbyname('Script').assign(cmds);
    cmds.free;
    post;
  end;
  table.free;
  SetupEvents;
  if didfind then work:='Client Event Replaced:' else work:='Client Event Added:';
  if docase then work:=work+'  -Case Sensitive';
  if dofilt then work:=work+'  -Filtered';
  if doret then work:=work+'  -Retained';
  if doterm then work:=work+'  -Terminal';
  SystemText(work,0);
  work2:=copy(egroup,1,15);
  work3:=copy(eevent,1,25);
  fmtstr(work,'  %-15s  %-25s                                   ',[work2,work3]);
  SystemText('  Group            Event      '+
    '                                                 ',1);
  SystemText(work,0);
end;

function TFormMain.NormalizeData(data: string): string;
var ch: string;
begin
  ch:=Datawell.TableOptions.fieldbyname('Activator').asstring;
  data:=Datawell.subs('~'+ch,Datawell.specialcode,data);
  data:=Datawell.subs(ch+ch,ch+' '+ch,data); //double activator characters = space commands
  data:=Datawell.subs('  ',' ',data);
  result:=Datawell.CutTrailingSpaces(data);
end;

function TFormMain.ParseRepeat(data: string): boolean;
var i, p: integer;
begin
  if copy(data,1,6) <> 'repeat' then exit(false);
  delete(data,1,6);
  result:=true;
  if copy(data,1,1) <> ' ' then begin
    if Datawell.repeatstring <> '' then
      SystemText('Repeating: "'+Datawell.repeatstring+'" every '+
        inttostr(TimerRepeat.interval div 1000)+'sec (Hit ESC to stop)',0)
    else SystemText('Not currently repeating anything',0);
    exit;
  end;
  delete(data,1,1);
  if length(data) < 1 then begin
    SystemText('Format is: '+Datawell.TableOptions.fieldbyname('Activator').asstring+
      'repeat <command>;<interval>',0);
    exit;
  end;
  if (recording) and (EditAlias.visible) then begin
    systemtext('You cannot set a repeater when recording an alias',0);
    exit;
  end;
  p:=pos(Datawell.TableOptions.fieldbyname('Activator').asstring,data);
  if(p > 0) then begin
    Datawell.repeatstring:=copy(data,1,p-1);
    i:=Datawell.toint(copy(data,p+1,9999));
  end
  else begin
    Datawell.repeatstring:=data;
    i:=2;
  end;
  if(i < 1) then i:=1;
  if(i > 100000) then i:=100000;
  TimerRepeat.interval:=i*1000;
  SystemText('Repeating: "'+Datawell.repeatstring+'" every '+
    inttostr(i)+'sec (Hit ESC to stop)',0);
  TimerRepeat.enabled:=false;
  TimerRepeat.enabled:=true;
end;

function TFormMain.ParseAlias(data: string): boolean;
var
  work, alias, original: string;
  i, amt2: integer;
  cmds: TStringList;
  didfind: boolean;
  table: TClientDataset;
begin
  work:='';
  result:=false;
  if copy(data,1,3) = 'ra ' then begin
    original:=data;
    delete(data,1,1);
    if copy(data,1,1) <> 'a' then exit;
    delete(data,1,1);
    if copy(data,1,1) <> ' ' then exit;
    data:=Datawell.CutLeadingspaces(data);
    if data = '' then exit;
    result:=true;
    if DoDelaying(original) then exit;
    if (recording) and (EditAlias.visible) then begin
      systemtext('You cannot edit aliases when recording an alias',0);
      exit;
    end;
    data:=Datawell.subs('"','',data);
    didfind:=false;
    table:=TClientDataset.create(self);
    table.CloneCursor(Datawell.TableAliases, false);
    table.filtered := true;
    table.active:=true;
    didfind := table.Locate('Alias', data, []);
    if didfind then begin
      SystemText('Client alias "'+table.fieldbyname('Alias').asstring+'" deleted',0);
      table.delete;
    end
    else SystemText('Client alias "'+data+'" does not exist',0);
    table.free;
    exit;
  end;
  if copy(data,1,1) <> 'a' then exit;
  result:=true;
  if DoDelaying(data) then exit;
  delete(data,1,1);
  data:=NormalizeData(data);
  if data = '' then begin
    SystemText('Client aliases defined (# of commands in [])',1);
    table:=TClientDataset.create(self);
    table.CloneCursor(Datawell.TableAliases, false);
    table.filtered := true;
    table.active:=true;
    table.first;
    amt2:=0;
    cmds:=TStringList.create;
    while not table.EOF do begin
      cmds.assign(table.fieldbyname('Script'));
      fmtstr(work,'  [%3d] %-71s',[cmds.count,table.fieldbyname('Alias').asstring]);
      SystemText(work,0);
      inc(amt2);
      table.next;
    end;
    cmds.free;
    if amt2 < 1 then SystemText('  <no client aliases exist>',0);
    table.free;
    exit;
  end;
  if copy(data,1,1) <> ' ' then begin
    result:=false;
    exit;
  end;
  if (recording) and (EditAlias.visible) then begin
    systemtext('You cannot edit aliases when recording an alias',0);
    exit;
  end;
  data:=Datawell.CutLeadingSpaces(data);
  i:=pos(' ',data);
  if i < 1 then begin
    data:=Datawell.subs('"','',data);
    didfind:=false;
    table:=TClientDataset.create(self);
    table.CloneCursor(Datawell.TableAliases, false);
    table.filtered := true;
    table.active:=true;
    didfind := table.Locate('Alias', data, []);
    if not didfind then begin
      SystemText('Client alias "'+data+'" does not exist',0);
      table.free;
      exit;
    end;
    SystemText('Commands for client alias: '+data,1);
    cmds:=TStringList.create;
    cmds.assign(table.fieldbyname('Script'));
    table.free;
    for i:=0 to cmds.count-1 do begin
      fmtstr(work,'%3d) %-74s',[i+1,cmds[i]]);
      SystemText(work,0);
    end;
    if cmds.count < 1 then SystemText('  <there are no commands assigned to this alias>',0);
    cmds.free;
    exit;
  end;
  alias:=copy(data,1,i-1);
  alias:=Datawell.subs('"','',alias);
  if not Datawell.ValidAlias(alias) then begin
    SystemText('Alias names cannot include a space " - '+
      Datawell.TableOptions.fieldbyname('Activator').asstring+' or begin with -',0);
    exit;
  end;
  if length(alias) > 60 then begin
    SystemText('Aliases cannot be longer than 60 characters',0);
    exit;
  end;
  alias:=Datawell.subs(Datawell.specialcode,'',alias);
  delete(data,1,i);
  table:=TClientDataset.create(self);
  table.CloneCursor(Datawell.TableAliases, false);
  table.filtered := true;
  table.active:=true;
  didfind := table.Locate('Alias', alias, []);
  i:=pos(Datawell.TableOptions.fieldbyname('Activator').asstring,data);
  cmds:=TStringList.create;
  while (i >= 1) and (length(data) > 1) do begin
    work:=copy(data,1,i-1);
    work:=Datawell.subs(Datawell.specialcode,
      Datawell.TableOptions.fieldbyname('Activator').asstring,work);
    cmds.add(work);
    delete(data,1,i);
    i:=pos(Datawell.TableOptions.fieldbyname('Activator').asstring,data);
  end;
  if length(data) > 0 then begin
    data:=Datawell.subs(Datawell.specialcode,
      Datawell.TableOptions.fieldbyname('Activator').asstring,data);
    cmds.add(data);
  end;
  if didfind then begin
    SystemText('Client alias "'+alias+'" replaced',1);
    table.edit;
  end
  else begin
    SystemText('Client alias "'+alias+'" added',1);
    table.append;
  end;
  table.fieldbyname('Master').asinteger:=Datawell.masterinteger;
  table.fieldbyname('Alias').asstring:=alias;
  table.fieldbyname('Script').assign(cmds);
  table.post;
  table.free;
  for i:=0 to cmds.count-1 do begin
    fmtstr(work,'%3d) %-74s',[i+1,cmds[i]]);
    SystemText(work,0);
  end;
  cmds.free;
end;

function TFormMain.ParseMacro(data: string): boolean;
var
  work, macro, original: string;
  i, amt2: integer;
  cmds: TStringList;
  didfind: boolean;
  table: TClientDataset;
begin
  work:='';
  result:=false;
  if copy(data,1,3) = 'rm ' then begin
    original:=data;
    delete(data,1,1);
    if copy(data,1,1) <> 'm' then exit;
    delete(data,1,1);
    if copy(data,1,1) <> ' ' then exit;
    data:=Datawell.CutLeadingspaces(data);
    if data = '' then exit;
    result:=true;
    if DoDelaying(original) then exit;
    if (recording) and (EditMacro.visible) then begin
      systemtext('You cannot edit macros when recording a macro',0);
      exit;
    end;
    data:=lowercase(data);
    data:=Datawell.cap(data);
    data:=Datawell.subs('"','',data);
    didfind:=false;
    table:=TClientDataset.create(self);
    with table do begin
      CloneCursor(Datawell.TableMacros, false);
      filtered := true;
      active:=true;
      first;
      while not EOF do begin
        if fieldbyname('Macro').asstring = data then begin
          didfind:=true;
          break;
        end;
        next;
      end;
      if didfind then begin
        SystemText('Client macro "'+fieldbyname('Macro').asstring+'" cleared',0);
        cmds:=TStringList.create;
        edit;
        fieldbyname('Script').assign(cmds);
        post;
        cmds.free;
      end
      else SystemText('Client macro "'+data+'" does not exist',0);
    end;
    table.free;
    exit;
  end;
  if copy(data,1,1) <> 'm' then exit;
  result:=true;
  if DoDelaying(data) then exit;
  delete(data,1,1);
  data:=NormalizeData(data);
  if data = '' then begin
    SystemText('Client macros with existing script (# of commands in [])',1);
    table:=TClientDataset.create(self);
    with table do begin
      CloneCursor(Datawell.TableMacros, false);
      filtered := true;
      active:=true;
      first;
      amt2:=0;
      cmds:=TStringList.create;
      while not EOF do begin
        cmds.assign(fieldbyname('Script'));
        if cmds.count > 0 then begin
          fmtstr(work,'  [%3d] %-71s',[cmds.count,fieldbyname('Macro').asstring]);
          SystemText(work,0);
          inc(amt2);
        end;
        next;
      end;
      cmds.free;
    end;
    table.free;
    if amt2 < 1 then SystemText('  <no client macros have an existing script>',0);
    exit;
  end;
  if copy(data,1,1) <> ' ' then begin
    result:=false;
    exit;
  end;
  if (recording) and (EditMacro.visible) then begin
    systemtext('You cannot edit macros when recording a macro',0);
    exit;
  end;
  data:=Datawell.CutLeadingSpaces(data);
  i:=pos(' ',data);
  if i < 1 then begin
    data:=lowercase(data);
    data:=Datawell.cap(data);
    data:=Datawell.subs('"','',data);
    didfind:=false;
    table:=TClientDataset.create(self);
    with table do begin
      CloneCursor(Datawell.TableMacros, false);
      filtered := true;
      active:=true;
      first;
      while not EOF do begin
        if fieldbyname('Macro').asstring = data then begin
          didfind:=true;
          break;
        end;
        next;
      end;
    end;
    if not didfind then begin
      SystemText('Client macro "'+data+'" does not exist',0);
      table.free;
      exit;
    end;
    SystemText('Commands for client macro: '+data,1);
    cmds:=TStringList.create;
    cmds.assign(table.fieldbyname('Script'));
    for i:=0 to cmds.count-1 do begin
      fmtstr(work,'%3d) %-74s',[i+1,cmds[i]]);
      SystemText(work,0);
    end;
    if cmds.count < 1 then SystemText('  <there are no commands assigned to this macro>',0);
    cmds.free;
    table.free;
    exit;
  end;
  macro:=copy(data,1,i-1);
  macro:=lowercase(macro);
  macro:=Datawell.cap(macro);
  macro:=Datawell.subs('"','',macro);
  macro:=Datawell.subs(Datawell.specialcode,'',macro);
  delete(data,1,i);
  didfind:=false;
  table:=TClientDataset.create(self);
  with table do begin
    CloneCursor(Datawell.TableMacros, false);
    filtered := true;
    active:=true;
    first;
    while not EOF do begin
      if lowercase(fieldbyname('Macro').asstring) = lowercase(macro) then begin
        didfind:=true;
        break;
      end;
      next;
    end;
  end;
  if not didfind then begin
    SystemText('Client macro "'+macro+'" not found',1);
    table.free;
    exit;
  end;
  i:=pos(Datawell.TableOptions.fieldbyname('Activator').asstring,data);
  cmds:=TStringList.create;
  while (i >= 1) and (length(data) > 1) do begin
    work:=copy(data,1,i-1);
    work:=Datawell.subs(Datawell.specialcode,
      Datawell.TableOptions.fieldbyname('Activator').asstring,work);
    cmds.add(work);
    delete(data,1,i);
    i:=pos(Datawell.TableOptions.fieldbyname('Activator').asstring,data);
  end;
  if length(data) > 0 then begin
    data:=Datawell.subs(Datawell.specialcode,
      Datawell.TableOptions.fieldbyname('Activator').asstring,data);
    cmds.add(data);
  end;
  SystemText('Client macro "'+macro+'" assigned',1);
  table.edit;
  table.fieldbyname('Script').assign(cmds);
  table.post;
  table.free;
  for i:=0 to cmds.count-1 do begin
    fmtstr(work,'%3d) %-74s',[i+1,cmds[i]]);
    SystemText(work,0);
  end;
  cmds.free;
end;

function TFormMain.QuickCharActionRQ(data: string): boolean;
var
   table: TClientDataset;
   original: string;
begin
   result := false;
   original:=data;
   assert(copy(data,1,3) = 'rq ');
   delete(data,1,3);
   data:=Datawell.CutLeadingspaces(data);
   if data = '' then exit;
   result:=true;
   if DoDelaying(original) then exit;
   data:=Datawell.subs('"','',data);
   Datawell.TableChars.filter := '(Character = '''+data+''')';
   Datawell.TableChars.filtered := true;
   Datawell.TableChars.active:=true;
   if Datawell.TableChars.fieldbyname('Character').asstring = '' then begin
      SystemText('Client quickchar "'+data+'" does not exist',0);
      exit;
   end;
   table:=TClientDataset.create(self);
   table.CloneCursor(Datawell.TableActions, false);
   if (table.Locate('Master;Character', VarArrayOf([Datawell.masterindex, data]), []))
     and (table.fieldbyname('Action').asstring <> '') then
   begin
      table.delete;
      SystemText('Client quickchar "'+data+'" cleared',0);
   end
   else SystemText('Client quickchar "'+data+'" not set to anything',0);
   table.free;
end;

procedure TFormMain.QuickCharActionQuery();
var
   amt: integer;
   action, work: string;
begin
   SystemText('Client quickchars defined',1);
   Datawell.TableChars.filter := '';
   Datawell.TableChars.filtered := true;
   Datawell.TableChars.active:=true;
   Datawell.TableChars.first;
   amt:=0;
   while not Datawell.TableChars.EOF do begin
      action := Datawell.TableActions.Lookup(
         'Master;Character',
         VarArrayOf([Datawell.masterindex, Datawell.TableChars.fieldbyname('Character').asstring]),
         'Action');
      if action <> '' then begin
         fmtstr(work,'%3s - %-73s',
            [Datawell.TableChars.fieldbyname('Character').asstring, action]);
         SystemText(work,0);
         inc(amt);
      end;
      Datawell.TableChars.next;
   end;
   if amt < 1 then SystemText('  <no client quickchars have commands attached>',0);
   exit;
end;

function TFormMain.ParseQuickchar(data: string): boolean;
var
  work, qchar, original, action: string;
  i, amt: integer;
  table: TClientDataset;
  didfind: boolean;
begin
  result:=false;
  if copy(data,1,3) = 'rq ' then begin
    exit(QuickCharActionRQ(data));
  end;
  if copy(data,1,1) <> 'q' then exit;
  result:=true;
  if DoDelaying(data) then exit;
  delete(data,1,1);
  data:=Datawell.subs('  ',' ',data); //no double spaces
  data:=Datawell.CutTrailingSpaces(data); //no trailing spaces
  if data = '' then begin
    QuickCharActionQuery;
    Exit;
  end;
  if copy(data,1,1) <> ' ' then begin
    result:=false;
    exit;
  end;
  data:=Datawell.CutLeadingSpaces(data); //no leading spaces
  i:=pos(' ',data);
  if i < 1 then begin
    didfind:=false;
    Datawell.TableChars.first;
    while not Datawell.TableChars.EOF do begin
      if Datawell.TableChars.fieldbyname('Character').asstring = data then begin
        didfind:=true;
        break;
      end;
      Datawell.TableChars.next;
    end;
    if not didfind then begin
      SystemText('Client quickchar "'+data+'" does not exist',0);
      exit;
    end;
    SystemText('Command for client quickchar: '+data,1);
    table:=TClientDataset.create(self);
    table.CloneCursor(Datawell.TableActions, false);
    table.filter := '(Master = '+Datawell.masterindex+') and (Character = '''+data+''')';
    table.filtered := true;
    table.active:=true;
    table.first;
    amt:=0;
    while not table.EOF do begin
      inc(amt);
      fmtstr(work,'  %-77s',[table.fieldbyname('Action').asstring]);
      SystemText(work,0);
      table.next;
    end;
    table.free;
    if amt < 1 then SystemText('  <no command assigned to this quickchar>',0);
    exit;
  end;
  qchar:=copy(data,1,i-1);
  delete(data,1,i);
  didfind:=false;
  with Datawell.TableChars do begin
    first;
    while not EOF do begin
      if fieldbyname('Character').asstring = qchar then begin
        didfind:=true;
        break;
      end;
      next;
    end;
  end;
  if not didfind then begin
    SystemText('Client quickchar "'+qchar+'" does not exist',0);
    exit;
  end;
  table:=TClientDataset.create(self);
  table.CloneCursor(Datawell.TableActions, false);
  table.filter := '(Master = '+Datawell.masterindex+') and (Character = '''+qchar+''')';
  table.filtered := true;
  table.active:=true;
  table.first;
  if table.fieldbyname('Action').asstring <> '' then begin
    SystemText('Client quickchar "'+qchar+'" replaced',1);
    while not table.EOF do table.delete;
  end
  else SystemText('Client quickchar "'+qchar+'" assigned',1);
  table.append;
  table.fieldbyname('Master').asinteger:=Datawell.masterinteger;
  table.fieldbyname('Character').asstring:=qchar;
  table.fieldbyname('Action').asstring:=data;
  table.post;
  table.free;
  fmtstr(work,'  %-77s',[data]);
  SystemText(work,0);
end;

function TFormMain.ParseVariables(data: string): boolean;
var
  work: string;
  amt: integer;
  table: TClientDataset;
begin
  result:=false;
  if copy(data,1,1) <> 'v' then exit;
  result:=true;
  if DoDelaying(data) then exit;
  delete(data,1,1);
  if data = '' then begin
    SystemText('Client variables defined',0);
    SystemText('  Variable                   Value           '+
      '                                  ',1);
    amt:=0;
    table:=TClientDataset.create(self);
    with table do begin
      CloneCursor(Datawell.TableVariables, false);
      filtered := true;
      active:=true;
      first;
      while not EOF do begin
        inc(amt);
        fmtstr(work,'  %-25s  %-50s',
          [fieldbyname('FVariable').asstring,fieldbyname('FValue').asstring]);
        SystemText(work,0);
        next;
      end;
    end;
    table.free;
    if amt < 1 then SystemText('  <no variables defined>',0);
    exit;
  end;
  if copy(data,1,1) <> ' ' then result:=false;
end;

function TFormMain.ParseSecondary(data: string): boolean;
var odata: string;
begin
  result:=false;
  if copy(data,1,1) <> 's' then exit;
  delete(data,1,1);
  odata:=copy(data,2,9999);
  data:=lowercase(data);
  if data = '' then begin
    if not Datawell.connected2 then data:=' c'
    else data:=' r';
  end;
  if copy(data,1,1) <> ' ' then exit;
  result:=true;
  if DoDelaying(data) then exit;
  delete(data,1,1);
  if (data = 'connect') or (data = 'c') then begin
    if Datawell.connected2 then begin
      SystemText('You must disconnect from '+Telnet2.host+':'+Telnet2.port+' first',0);
      exit;
    end;
    MenuSecondary.click;
    exit;
  end
  else if (data = 'disconnect') or (data = 'd') then begin
    if not Datawell.connected2 then begin
      SystemText('There is no current secondary connection',0);
      exit;
    end;
    MenuSecondaryDisconnect.click;
  end
  else if data = '1' then begin
    if not Datawell.connected2 then begin
      SystemText('There is no current secondary connection',0);
      SystemText('Connection remains at: Primary',0);
      exit;
    end;
    ChangeControl(1);
  end
  else if data = '2' then begin
    if not Datawell.connected2 then begin
      SystemText('There is no current secondary connection',0);
      exit;
    end;
    ChangeControl(2);
  end
  else if data = 'r' then begin
    if BtnMUD1.down then begin
      if not Datawell.connected2 then begin
        SystemText('There is no current secondary connection',0);
        SystemText('Connection remains at: Primary',0);
        exit;
      end;
      ChangeControl(2);
      exit;
    end;
    ChangeControl(1);
    exit;
  end
  else begin
    if BtnMUD2.down then begin
      if not Datawell.connected then systemtext('Not connected to primary connection',0)
      else begin
        MUDAnsi.InsertFormatedText(Datawell.TableOptions.fieldbyname('FColorTyped').asinteger,
          Datawell.TableOptions.fieldbyname('BColorTyped').asinteger,'1: '+odata+#10,false,false);
        Telnet.SendStr(odata+Datawell.cr);
      end;
    end
    else begin
      if not Datawell.connected2 then systemtext('Not connected to secondary connection',0)
      else begin
        MUDAnsi.InsertFormatedText(Datawell.TableOptions.fieldbyname('FColorTyped').asinteger,
          Datawell.TableOptions.fieldbyname('BColorTyped').asinteger,'2: '+odata+#10,false,false);
        Telnet2.SendStr(odata+Datawell.cr2);
      end;
    end;
  end;
end;

function TFormMain.ParseJumpstart(data: string): boolean;
begin
  result:=false;
  if data <> 'jumpstart' then exit;
  result:=true;
  if DoDelaying(data) then exit;
  MenuJumpstartClick(MenuJumpstart);
end;

function TFormMain.ParseSystem(data: string): boolean;
begin
  result:=false;
  if copy(data,1,7) = 'system ' then begin
    result:=true;
    if DoDelaying(data) then exit;
    delete(data,1,7);
    data:=Datawell.ReplaceFunctions(data);
    data:=Datawell.ReplaceVariables(data);
    SystemText('System: '+data,0);
  end
  else if copy(data,1,5) = 'break' then begin
    result:=true;
    ClearSending;
    systemtext('Command buffer cleared',0);
    exit;
  end
  else if copy(data,1,4) = 'next' then begin
    result:=true;
    systemtext('Skipping to next buffered command',0);
    MenuNext.click;
    exit;
  end
  else if copy(data,1,5) = 'panic' then begin
    result:=true;
    if not panicking then MenuPanic.click else SystemText('Already in panic mode',0)
  end;
end;

function TFormMain.ParseNickname(data: string): boolean;
var
  work, nick, original: string;
  i, amt: integer;
  table: TClientDataset;
begin
  result:=false;
  if copy(data,1,3) = 'rn ' then begin
    original:=data;
    delete(data,1,1);
    if copy(data,1,1) <> 'n' then exit;
    delete(data,1,1);
    if copy(data,1,1) <> ' ' then exit;
    data:=Datawell.CutLeadingspaces(data);
    if data = '' then exit;
    result:=true;
    if DoDelaying(original) then exit;
    data:=Datawell.subs('"','',data);
    table:=TClientDataset.create(self);
    with table do begin
      CloneCursor(Datawell.TableNicknames, false);
      filter := '(Master = '+Datawell.masterindex+') and (Nickname = '''+data+''')';
      filtered := true;
      active:=true;
      if fieldbyname('Nickname').asstring = '' then begin
        SystemText('Client nickname "'+data+'" does not exist',0);
        exit;
      end;
      while not EOF do delete;
    end;
    table.free;
    SystemText('Client nickname "'+data+'" deleted',0);
    exit;
  end;
  if copy(data,1,1) <> 'n' then exit;
  result:=true;
  if DoDelaying(data) then exit;
  delete(data,1,1);
  data:=Datawell.subs('  ',' ',data); //no double spaces
  data:=Datawell.CutTrailingSpaces(data); //no trailing spaces
  if data = '' then begin
    SystemText('Client nicknames defined (nickname/replacement)',1);
    amt:=0;
    table:=TClientDataset.create(self);
    with table do begin
      CloneCursor(Datawell.TableNicknames, false);
      filtered := true;
      active:=true;
      first;
      while not EOF do begin
        inc(amt);
        fmtstr(work,'  %-77s',
          [fieldbyname('Nickname').asstring+'/'+fieldbyname('Replacement').asstring]);
        SystemText(work,0);
        next;
      end;
    end;
    table.free;
    if amt < 1 then SystemText('  <no client nicknames exist>',0);
    exit;
  end;
  if copy(data,1,1) <> ' ' then begin
    result:=false;
    exit;
  end;
  data:=Datawell.CutLeadingSpaces(data); //no leading spaces
  i:=pos(' ',data);
  if i < 1 then begin
    SystemText('Format is: '+Datawell.TableOptions.fieldbyname('Activator').asstring+
      'nickname <nickname> <replacement>',0);
    exit;
  end;
  nick:=copy(data,1,i-1);
  delete(data,1,i);
  if pos('"',nick) > 0 then begin
    SystemText('Nicknames cannot contain quotes',0);
    exit;
  end;
  if length(nick) > 60 then begin
    SystemText('Nicknames cannot be longer than 60 characters',0);
    exit;
  end;
  table:=TClientDataset.create(self);
  with table do begin
    CloneCursor(Datawell.TableNicknames, false);
    filter := '(Master = '+Datawell.masterindex+') and (Nickname = '''+nick+''')';
    filtered := true;
    active:=true;
    if fieldbyname('Nickname').asstring <> '' then begin
      SystemText('Client nickname "'+data+'" already exists, replacing...',0);
      delete;
    end;
    append;
    fieldbyname('Master').asinteger:=Datawell.masterinteger;
    fieldbyname('Nickname').asstring:=nick;
    fieldbyname('Replacement').asstring:=data;
    post;
  end;
  table.free;
  SystemText('Client nickname/replacement "'+nick+'/'+data+'" added',0);
end;

procedure TFormMain.UpdateCaption;
var newcap: string;
begin
  newcap:=Datawell.mud+' - '+Datawell.player+' ('+FigureTimeString+')  ';
  if Datawell.connected2 then newcap:=newcap+'[2nd '+Telnet2.host+':'+Telnet2.port+']  ';
  if captionstring <> '' then newcap:=newcap+captionstring
  else begin
    if rebootstring <> '' then newcap:=newcap+rebootstring+'  ';
    if uptimestring <> '' then newcap:=newcap+uptimestring+'  ';
    if mudlagstring <> '' then newcap:=newcap+mudlagstring+'  ';
  end;
  caption:=newcap;
end;

procedure TFormMain.PanelHP3SplitMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  hp3mouseisdown:=true;
end;

procedure TFormMain.PanelHP3SplitMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  hp3mouseisdown:=false;
end;

procedure TFormMain.PanelHP4SplitMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  hp4mouseisdown:=true;
end;

procedure TFormMain.PanelHP4SplitMouseUp(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  hp4mouseisdown:=false;
end;

procedure TFormMain.PanelHP3SplitMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
var newoffset, offmin, offmax: integer;
begin
  if not hp3mouseisdown then begin
    LabelStatus.caption:='';
    exit;
  end;
  newoffset:=PanelHP3Split.left+x;
  offmin:=(PanelBars.width*10) div 100;
  offmax:=(PanelBars.width*85) div 100;
  if newoffset < offmin then newoffset:=offmin;
  if newoffset > offmax then newoffset:=offmax;
  PanelHP3Split.left:=newoffset;
end;

procedure TFormMain.PanelHP4SplitMouseMove(Sender: TObject;
  Shift: TShiftState; X, Y: Integer);
var newoffset, offmin, offmax: integer;
begin
  if not hp4mouseisdown then begin
    LabelStatus.caption:='';
    exit;
  end;
  newoffset:=PanelHP4Split.left+x;
  offmin:=(PanelBars.width*10) div 100;
  offmax:=(PanelBars.width*85) div 100;
  if newoffset < offmin then newoffset:=offmin;
  if newoffset > offmax then newoffset:=offmax;
  PanelHP4Split.left:=newoffset;
  UpdateHP4Bar;
end;

procedure TFormMain.UpdateHP4Bar;
var offmin, offmax: integer;
begin
  offmin:=(PanelBars.width*10) div 100;
  offmax:=(PanelBars.width*85) div 100;
  if PanelHP4Split.left < offmin then PanelHP4Split.left:=offmin;
  if PanelHP4Split.left > offmax then PanelHP4Split.left:=offmax;
  PanelSpecial.width:=PanelHP4Split.left;
  PanelSpecial2.left:=PanelHP4Split.left+5;
  PanelSpecial2.width:=PanelHP4Bar.width-PanelHP4Split.left-31;
  LabelSpecial.width:=PanelSpecial.width-2;
  LabelSpecial2.width:=PanelSpecial2.width-2;
end;

procedure TFormMain.UpdateMasks;
var a, b, c, d: string;
begin
  a:=Datawell.TableOptions.fieldbyname('GP1Mask').asstring;
  b:=Datawell.TableOptions.fieldbyname('GP2Mask').asstring;
  c:=Datawell.TableOptions2.fieldbyname('HPMask').asstring;
  d:=Datawell.TableOptions2.fieldbyname('SPMask').asstring;
  ImageGP12.hint:=a;
  GaugeGP1.hint:=a;
  ImageGP1.hint:=a;
  LabelGP1.hint:=a;
  LabelGP1Max.hint:='Maximum '+a;
  ImageGP22.hint:=b;
  GaugeGP2.hint:=b;
  ImageGP2.hint:=b;
  LabelGP2.hint:=b;
  LabelGP2Max.hint:='Maximum '+b;
  ImageHP2.hint:=c;
  GaugeHP.hint:=c;
  ImageHP.hint:=c;
  LabelHP.hint:=c;
  LabelHPMax.hint:='Maximum '+c;
  ImageSP2.hint:=d;
  GaugeSP.hint:=d;
  ImageSP.hint:=d;
  LabelSP.hint:=d;
  LabelSPMax.hint:='Maximum '+d;
end;

procedure TFormMain.MenuFindClick(Sender: TObject);
var
  str: string;
  ret: integer;
  form: TFormEnterText;
begin
  str:=EditSend.text;
  if str = '' then begin
    form:=TFormEnterText.create(self);
    form.showmodal;
    str:=form.replacement;
    form.free;
  end;
  if str = '' then exit;
  EditSend.text:='';
  Scrollback.unselect;
  if PanelScroll.height < 1 then MenuDoScrollbackClick(sender);
  ret:=Scrollback.find(str);
  if ret = 0 then messagedlg('Text "'+str+'" not found',mtinformation,[mbok],0);
  if ret = 1 then findtext:=str;
  UpdateScrollbackLabels;
end;

procedure TFormMain.MenuFindNextClick(Sender: TObject);
var
  str: string;
  ret: integer;
begin
  str:=findtext;
  if findtext = '' then exit;
  if PanelScroll.height < 1 then MenuDoScrollbackClick(sender);
  ret:=Scrollback.findnext(str);
  if ret = 0 then messagedlg('Text "'+str+'" not found',mtinformation,[mbok],0);
  UpdateScrollbackLabels;
end;

procedure TFormMain.MenuSendPasswordClick(Sender: TObject);
var
  form: TFormFPassword;
  data: string;
begin
  data:='';
  if (not Datawell.connected) and (not Datawell.connected2) then begin
    messagedlg('Not connected to server',mtinformation,[mbok],0);
    exit;
  end;
  form:=TFormFPassword.create(self);
  form.caption:='Masked Text';
  form.EditPassword.maxlength:=255;
  form.LabelTitle.caption:='Enter the masked text';
  form.Label1.caption:='Masked Text';
  form.BtnNone.hide;
  form.BtnOK.left:=84;
  form.BtnCancel.left:=227;
  form.showmodal;
  data:=form.password;
  form.free;
  if data = '' then exit;
  if (Datawell.connected) or (Datawell.connected2) then begin
    if BtnMUD1.down then Telnet.SendStr(data+Datawell.cr)
    else Telnet2.SendStr(data+Datawell.cr2);
  end;
  SystemText('((Masked Text Sent))',0);
end;

function TFormMain.ParseCycling(data: string; kind: integer): boolean;
var
  pre, suf, work: string;
  i, numfrom, numto: integer;
  reversed: boolean;
begin
  result:=false;
  reversed:=false;
  if copy(data,1,6) <> 'cycle ' then exit;
  result:=true;
  delete(data,1,6);
  i:=pos('-',data);
  if i < 1 then begin
    SystemText('Format is: '+Datawell.TableOptions.fieldbyname('Activator').asstring+
      'cycle <#from>-<#to> <command>',0);
    exit;
  end;
  pre:=copy(data,1,i-1);
  pre:=Datawell.ReplaceFunctions(pre);
  pre:=Datawell.ReplaceVariables(pre);
  delete(data,1,i);
  i:=pos(' ',data);
  if i < 1 then begin
    SystemText('Format is: '+Datawell.TableOptions.fieldbyname('Activator').asstring+
      'cycle <#from>-<#to> <command>',0);
    exit;
  end;
  suf:=copy(data,1,i-1);
  suf:=Datawell.ReplaceFunctions(suf);
  suf:=Datawell.ReplaceVariables(suf);
  delete(data,1,i);
  numfrom:=Datawell.toint(pre);
  numto:=Datawell.toint(suf);
  if numfrom > numto then reversed:=true;
  if abs(numto-numfrom) > 98 then begin
    SystemText('The maximum number of commands you can cycle is 99',0);
    exit;
  end;
  if kind = 1 then kind:=10;
  if not reversed then begin
    for i:=numfrom to numto do begin
      work:=data;
      work:=Datawell.subs('$',inttostr(i),work);
      ParseMain(work,kind);
    end;
  end
  else begin
    for i:=numfrom downto numto do begin
      work:=data;
      work:=Datawell.subs('$',inttostr(i),work);
      ParseMain(work,kind);
    end;
  end
end;

procedure TFormMain.PopupHP3Click(Sender: TObject);
var s: integer;
begin
  s:=TMenuItem(sender).tag;
  if s = 0 then s:=8
  else begin
    GLine1.selectall;
    s:=GLine1.selattributes.size+s;
  end;
  if s < 6 then s:=6;
  if s > 20 then s:=20;
  GLine1.selectall;
  GLine1.selattributes.size:=s;
  GLine1.selstart:=0;
  GLine1.sellength:=0;
  GLine1.font.size:=s;
  GLine2.selectall;
  GLine2.selattributes.size:=s;
  GLine2.selstart:=0;
  GLine2.sellength:=0;
  GLine2.font.size:=s;
end;

procedure TFormMain.PopupHP4Click(Sender: TObject);
var s: integer;
begin
  s:=TMenuItem(sender).tag;
  if s = 0 then s:=8
  else s:=LabelSpecial.font.size+s;
  if s < 6 then s:=6;
  if s > 20 then s:=20;
  LabelSpecial.font.size:=s;
  LabelSpecial2.font.size:=s;
end;

procedure TFormMain.MenuJumpstartClick(Sender: TObject);
var
  work: string;
  x: integer;
  frommudansi: boolean;
begin
  frommudansi:=false;
  if TComponent(sender).tag = 7777 then frommudansi:=true;
  if (not Datawell.connected) and (not Datawell.connected2) then begin
    if not frommudansi then
      systemtext('Not connected to server',0);
    exit;
  end;
  x:=random(Datawell.randommax);
  while ((x > 22000) and (x < 28000))
    or ((x > 32486) and (x < 33546))
    or ((x > 38475) and (x < 39567))
    or ((x > 51745) and (x < 59611))
    or ((x > 68746) and (x < 75461))
    or ((x > 87932) and (x < 92105))
    or (x < 10000)
    do x:=random(Datawell.randommax);
  Datawell.randomcode:=x;
  MUDAnsi.increment:=Datawell.randomcode;
  Telnet.SendStr('3klient '+inttostr(Datawell.randomcode)+
    Datawell.delim+'Po'+Datawell.version2+Datawell.cr);
  if frommudansi then begin
    MUDAnsi.enablejumpstart:=false;
    work:=Datawell.TableOptions.fieldbyname('LoginMacro').asstring;
    if work <> '' then DoMacro(work,0,false);
  end
  else begin
    Telnet.resume;
    SystemText('((Jumpstart Command Sent))',0);
  end;
end;

procedure TFormMain.ListHistoryDrawItem(Control: TWinControl;
  Index: Integer; Rect: TRect; State: TOwnerDrawState);
begin
  gaugehp.progress:=20+random(60);
end;

procedure TFormMain.ListHistoryMeasureItem(Control: TWinControl;
  Index: Integer; var Height: Integer);
begin
  gaugesp.progress:=20+random(60);
end;

procedure TFormMain.ClearStatusFields;
begin
  if screens[4] then begin
    screenImagery.LabelText.caption:='';
    screenImagery.GaugeEnemy.progress:=0;
  end;
  LabelHP.caption:='';
  LabelSP.caption:='';
  LabelGP1.caption:='';
  LabelGP2.caption:='';
  LabelHPMax.caption:='';
  LabelSPMax.caption:='';
  LabelGP1Max.caption:='';
  LabelGP2Max.caption:='';
  GaugeEnemy.progress:=0;
  GaugeEnemy2.progress:=0;
  GaugeHP.progress:=0;
  GaugeSP.progress:=0;
  GaugeGP1.progress:=0;
  GaugeGP2.progress:=0;
  GLine1.lines.clear;
  GLine2.lines.clear;
  LabelSpecial.caption:='';
  LabelSpecial2.caption:='';
  enemys[0]:=true;
  enemys[1]:=false;
  enemys[2]:=false;
  enemys[3]:=false;
  enemys[4]:=false;
  if Datawell.TableOptions3.FieldByName('L29').asboolean then begin
    ImageEnemy.visible:=enemys[0];
    ImageEnemyLow.visible:=enemys[1];
    ImageEnemyMedian.visible:=enemys[2];
    ImageEnemyHigh.visible:=enemys[3];
    ImageEnemyBetter.visible:=enemys[4];
    ImageEnemy2.visible:=enemys[0];
    ImageEnemyLow2.visible:=enemys[1];
    ImageEnemyMedian2.visible:=enemys[2];
    ImageEnemyHigh2.visible:=enemys[3];
    ImageEnemyBetter2.visible:=enemys[4];
  end;
end;

procedure TFormMain.MenuInsertBeepClick(Sender: TObject);
begin
  MemoPaste.lines.clear;
  MemoPaste.pastefromclipboard;
  EditBeep.selectall;
  EditBeep.copytoclipboard;
  EditSend.pastefromclipboard;
  MemoPaste.selectall;
  MemoPaste.copytoclipboard;
end;

procedure TFormMain.PopupUndoClick(Sender: TObject);
begin
  case TMenuItem(sender).tag of
    1: begin
         with EditSend do begin
           if HandleAllocated then SendMessage(Handle,EM_UNDO,0,0);
         end;
       end;
    3: EditSend.CuttoClipboard;
    4: EditSend.CopyToClipboard;
    5: begin
         MenuOpenAutotyperClick(Sender);
         MemoCopy.text:=EditSend.seltext;
         MemoCopy.selectall;
         MemoCopy.CopyToClipboard;
         if screens[11] then screenEditor.ActiveEditor.PasteFromClipboard;
       end;
  end;
end;

procedure TFormMain.PopupCommandLinePopup(Sender: TObject);
var en: boolean;
begin
  if EditSend.seltext <> '' then en:=true else en:=false;
  PopupCut.enabled:=en;
  PopupCopy.enabled:=en;
  PopupCopyA.enabled:=en;
end;

procedure TFormMain.MenuCopyDownloadClick(Sender: TObject);
var
  F: TextFile;
  work: string;
  i: integer;
begin
  DialogSave.initialdir:=Datawell.GetDir(5);
  DialogSave.filename:=DownloadString;
  if not DialogSave.execute then exit;
  Datawell.SetDir(5,DialogSave.filename);
  work:=DialogSave.filename;
  while (length(work) > 0) and (work[length(work)] <> '\') do delete(work,length(work),1);
  AssignFile(F,DialogSave.filename);
  Rewrite(F);
  for i:=0 to Download.count-1 do begin
    WriteLn(F,Download[i]);
  end;
  CloseFile(F);
end;

procedure TFormMain.MenuClearDownloadClick(Sender: TObject);
begin
  Downloading:=false;
  Download.clear;
  LEDDownloadF.bringtofront;
  PopupCopyDownloadA.caption:='&Replace Contents of Autotyper with Download';
  PopupPasteCursor.caption:='&Paste Download into Autotyper at Cursor';
  PopupCaptureDownload.caption:='&Capture Download to File';
  PanelDownload.hide;
  UpdateDownloadButtons;
end;

procedure TFormMain.UpdateDownloadButtons;
var ena: boolean;
begin
  if Download.count > 0 then ena:=true else ena:=false;
  MenuCopyDownloadA.enabled:=ena;
  PopupCopyDownloadA.enabled:=ena;
  BtnDownloadA.enabled:=ena;
  MenuPasteCursor.enabled:=ena;
  PopupPasteCursor.enabled:=ena;
  BtnPasteCursor.enabled:=ena;
  MenuCopyDownload.enabled:=ena;
  PopupCaptureDownload.enabled:=ena;
  BtnDownloadF.enabled:=ena;
  ena:=true;
  MenuClearDownload.enabled:=ena;
  PopupClearDownload.enabled:=ena;
  BtnClearDownload.enabled:=ena;
end;

procedure TFormMain.UpdateAutotyperButtons(ena: boolean);
begin
  MenuAutotype.enabled:=ena;
  BtnAutotype.enabled:=ena;
end;

function TFormMain.FigureFColor(kind: integer): integer;
begin
  case kind of
    2: result:=Datawell.TableOptions.fieldbyname('FColorAutotyper').asinteger;
    3: result:=Datawell.TableOptions.fieldbyname('FColorAliases').asinteger;
    4: result:=Datawell.TableOptions.fieldbyname('FColorMacros').asinteger;
    5: result:=Datawell.TableOptions.fieldbyname('FColorEvents').asinteger;
    6: result:=Datawell.TableOptions.fieldbyname('FColorPasted').asinteger;
    7: result:=Datawell.TableOptions.fieldbyname('FColorQuickchars').asinteger;
    9: result:=Datawell.TableOptions.fieldbyname('FColorTicker').asinteger;
    10: result:=Datawell.TableOptions.fieldbyname('FColorParsed').asinteger;
    else result:=Datawell.TableOptions.fieldbyname('FColorTyped').asinteger;
  end;
end;

function TFormMain.FigureBColor(kind: integer): integer;
begin
  case kind of
    2: result:=Datawell.TableOptions.fieldbyname('BColorAutotyper').asinteger;
    3: result:=Datawell.TableOptions.fieldbyname('BColorAliases').asinteger;
    4: result:=Datawell.TableOptions.fieldbyname('BColorMacros').asinteger;
    5: result:=Datawell.TableOptions.fieldbyname('BColorEvents').asinteger;
    6: result:=Datawell.TableOptions.fieldbyname('BColorPasted').asinteger;
    7: result:=Datawell.TableOptions.fieldbyname('BColorQuickchars').asinteger;
    9: result:=Datawell.TableOptions.fieldbyname('BColorTicker').asinteger;
    10: result:=Datawell.TableOptions.fieldbyname('BColorParsed').asinteger;
    else result:=Datawell.TableOptions.fieldbyname('BColorTyped').asinteger;
  end;
end;

function TFormMain.FigureEcho(kind: integer): boolean;
begin
  case kind of
    2: result:=Datawell.TableOptions.fieldbyname('Autotyper').asboolean;
    3: result:=Datawell.TableOptions.fieldbyname('Aliases').asboolean;
    4: result:=Datawell.TableOptions.fieldbyname('Macros').asboolean;
    5: result:=Datawell.TableOptions.fieldbyname('Events').asboolean;
    6: result:=Datawell.TableOptions.fieldbyname('Pasted').asboolean;
    7: result:=Datawell.TableOptions.fieldbyname('EQuickchars').asboolean;
    9: result:=Datawell.TableOptions.fieldbyname('ETicker').asboolean;
    10: result:=Datawell.TableOptions.fieldbyname('EParsed').asboolean;
    else result:=Datawell.TableOptions.fieldbyname('Typed').asboolean;
  end;
end;

procedure TFormMain.LEDImageFilterClick(Sender: TObject);
begin
  MenuShowFiltered.click;
end;

procedure TFormMain.PlaySound(filename: string; now, system, forced: integer; panicforced: boolean);
var
  work, ofile: string;
  didfail: boolean;
begin
  if not panicforced then begin
    if haltsounds then exit;
    if forced < 1 then begin
      if (system = 1) and (not Datawell.TableOptions.fieldbyname('Sounds').asboolean) then exit;
      if (system = 0) and (not Datawell.TableOptions.fieldbyname('EventSounds').asboolean) then exit;
    end;
  end;
  if length(filename) < 1 then exit;
  ofile:=filename;
  filename:=lowercase(filename);
  //Check if it's a filename without an extension
  if pos('.',filename) < 1 then begin
    //Look for an existing wav file
    work:=Datawell.getsounddir+'\'+filename+'.wav';
    //If it's not a wav, try an mp3
    if not fileexists(work) then work:=Datawell.getsounddir+'\'+filename+'.mp3';
    //If it's not an mp3, it's screwed
    if not fileexists(work) then exit;
    filename:=work;
  end;
  work:=copy(filename,length(filename)-3,4);
  if (work = '.mid') or (work = '.rmi') or (work = '.mp3') then begin //Force a song
    if not fileexists(filename) then filename:=Datawell.getsounddir+'\'+filename;
    if not fileexists(filename) then exit;
    MP2.filename:=filename;
    didfail:=false;
    try MP2.open; except on EMCIDeviceError do didfail:=true; end;
    if didfail then exit;
    MP2.play;
    exit;
  end;
  if copy(filename,length(filename)-3,4) <> '.wav' then filename:=filename+'.wav';
  if not fileexists(filename) then filename:=Datawell.getsounddir+'\'+filename;
  if not fileexists(filename) then exit;
  try sndplaysound(pchar(filename),(snd_async or snd_nodefault));
  except on EExternalException do end;
end;

procedure TFormMain.MenuMusicPlayClick(Sender: TObject);
var
  isplaying: boolean;
  f: string;
begin
  case TComponent(sender).tag of
    1: begin
         if (MenuMusicRandomize.checked) and (MP.mode = mpplaying) then begin
           Datawell.playindex:=random(Datawell.playlist.count);
           PlayMusic(Datawell.playlist[Datawell.playindex],false);
         end
         else begin
           if (MP.mode = mpstopped) or (MP.mode = mppaused) then begin
             if BtnMusicPause.enabled then begin
               LabelStatus.font.color:=clwhite;
               PanelStatus.color:=clnavy;
               f:=extractfilename(Datawell.playlist[Datawell.playindex]);
               f:=copy(f,1,length(f)-4);
               LabelStatus.caption:=' Playing song: '+f;
               PanelStatus.repaint;
               TimerMusic.enabled:=false;
               TimerMusic.enabled:=true;
             end;
             MP.hint:='a';
             MP.play;
           end;
         end;
       end;
    0: begin
         if (MP.mode <> mpplaying) and (MP.mode <> mppaused) then exit;
         repeatmusic:=0;
         MP.hint:='a';
         MP.stop;
       end;
   -1: begin
         if (MP.mode <> mpstopped) and (MP.mode <> mpplaying) then exit;
         repeatmusic:=0;
         isplaying:=MP.mode = mpplaying;
         MP.hint:='a';
         MP.previous;
         if isplaying then MP.play;
       end;
  end;
  UpdateMusic;
end;

procedure TFormMain.MPNotify(Sender: TObject);
begin
  if MP.hint <> '' then exit;
  if not MenuMusicRepeat.checked then begin
    repeatmusic:=0;
    if MenuMusicRandomize.checked then
      Datawell.playindex:=random(Datawell.playlist.count)
    else begin
      if Datawell.playindex < Datawell.playlist.count-1 then inc(Datawell.playindex)
      else Datawell.playindex:=0;
    end;
  end;
  PlayMusic(Datawell.playlist[Datawell.playindex],false);
  if repeatmusic > 0 then begin
    if repeatmusic = 1 then MenuMusicRepeat.checked:=false;
    dec(repeatmusic);
  end;
  UpdateMusic;
end;

procedure TFormMain.MenuSendDelimitedClick(Sender: TObject);
var
  i: integer;
  str: string;
begin
  MemoPaste.lines.clear;
  MemoPaste.pastefromclipboard;
  str:='';
  for i:=0 to MemoPaste.lines.count-1 do begin
    str:=str+' '+MemoPaste.lines[i];
    if length(str) > 1000 then break;
  end;
  str:=Datawell.CutLeadingSpaces(str);
  str:=Datawell.CutTrailingSpaces(str);
  if TMenuItem(sender).tag = 0 then str:=EditSend.text+' '+str;
  str:=Datawell.CutLeadingSpaces(str);
  str:=copy(str,1,500);
  if TMenuItem(sender).tag = 0 then ParseMain(str,6)
  else EditSend.text:=str;
end;

procedure TFormMain.MenuPasteCursorClick(Sender: TObject);
begin
  MemoPaste.lines.assign(Download);
  MemoPaste.selectall;
  MemoPaste.CopyToClipboard;
  MenuOpenAutotyperClick(Sender);
  if screens[11] then screenEditor.ActiveEditor.PasteFromClipboard;
end;

procedure TFormMain.MenuVarsClick(Sender: TObject);
var form: TFormVars;
begin
  Datawell.TableVariables.first;
  form:=TFormVars.create(self);
  form.showmodal;
  form.free;
  if not screens[10] then exit;
  screenCanvas.close;
  LoadScreen(10);
end;

procedure TFormMain.MenuUploadClick(Sender: TObject);
var work: string;
begin
  DialogOpen.initialdir:=Datawell.GetDir(5);
  if not DialogOpen.execute then exit;
  Datawell.SetDir(5,DialogOpen.filename);
  work:=DialogOpen.filename;
  while (length(work) > 0) and (work[length(work)] <> '\') do delete(work,length(work),1);
  Uploads.assign(DialogOpen.files);
  if Uploads.count = 1 then
    SystemText('<Uploading 1 File>',0)
  else SystemText('<Uploading '+inttostr(Uploads.count)+' Files>',0);
  PanelDownload.show;
  TimerUpload.interval:=100;
  TimerUpload.enabled:=true;
end;

procedure TFormMain.TimerUploadTimer(Sender: TObject);
var
  i: integer;
  work: string;
  flines: TStringList;
begin
  TimerUpload.interval:=2000;
  if Uploads.count > 0 then begin
    flines:=TStringList.create;
    try flines.loadfromfile(Uploads[0]);
      except on EFOpenError do begin
        SystemText('File in use, skipping: '+Uploads[0],0);
        Uploads.delete(0);
        flines.free;
        exit;
      end;
    end;
    work:=Uploads[0];
    while pos('\',work) > 0 do delete(work,1,pos('\',work));
    work:=Datawell.subs(' ','_',work);
    LabelDownload.caption:=work;
    GaugeDownload.progress:=0;
    SendData('3ksendfile '+work,888);
    GaugeDownload.maxvalue:=flines.count-1;
    for i:=0 to flines.count-1 do begin
      SendData(flines[i],888);
      GaugeDownload.progress:=i;
    end;
    SendData('EOF',888);
    SendData('',888);
    SystemText('++Uploaded: '+work,0);
    flines.free;
  end;
  Uploads.delete(0);
  if Uploads.count < 1 then begin
    PanelDownload.hide;
    SystemText('<Uploading Complete>',0);
    TimerUpload.enabled:=false;
  end;
end;

procedure TFormMain.BtnViewFilteredClick(Sender: TObject);
begin
  MenuShowFiltered.click;
end;

procedure TFormMain.MenuNextClick(Sender: TObject);
begin
  TimerSendTimer(Sender);
end;

procedure TFormMain.MenuClearBufferClick(Sender: TObject);
begin
  ClearSending;
end;

function TFormMain.ParseProcess(data: string): boolean;
begin
  result:=false;
  if (copy(data,1,8) <> 'process ') and (copy(data,1,8) <> 'compile ') then exit;
  result:=true;
  if DoDelaying(data) then exit;
  delete(data,1,8);
  if data = '' then begin
    SystemText('Format is: '+Datawell.TableOptions.fieldbyname('Activator').asstring+'process <code>',0);
    exit;
  end;
  Compile(data);
end;

procedure TFormMain.CommonScriptsClick(Sender: TObject);
var form: TFormUnits;
begin
  if (recording) and (EditMacro.visible) then begin
    messagedlg('You cannot edit common scripts when recording a macro',mtinformation,[mbok],0);
    exit;
  end;
  form:=TFormUnits.create(self);
  try
     form.showmodal;
  finally
     form.free;
  end;
end;

function TFormMain.Compile(data: string): string;
var
  literal, lvalue, zdata: string;
  i, kind: integer;
begin
  result:='';
  kind:=0;
  i:=pos('+=',data);
  if i > 1 then kind:=1
  else begin
    i:=pos('-=',data);
    if i > 1 then kind:=2
    else begin
      i:=pos('++',data);
      if i > 1 then kind:=3
      else begin
        i:=pos('--',data);
        if i > 1 then kind:=4
        else begin
          i:=pos('*=',data);
          if i > 1 then kind:=5
          else begin
            i:=pos('/=',data);
            if i > 1 then kind:=6
            else begin
              i:=pos('=',data);
              if i > 1 then kind:=999;
            end;
          end;
        end;
      end;
    end;
  end;
  if kind < 1 then exit;
  literal:=copy(data,1,i-1);
  if kind = 999 then delete(data,1,i)
  else delete(data,1,i+1);
  if copy(data,length(data),1) = ')' then data:=DoFunction(data);
  data:=Datawell.ReplaceFunctions(data);
  data:=Datawell.ReplaceVariables(data);
  if kind <> 999 then begin
    lvalue:=Datawell.ReplaceVariables(literal);
    case kind of
      1: data:=inttostr(Datawell.ToInt(lvalue)+Datawell.ToInt(data));
      2: data:=inttostr(Datawell.ToInt(lvalue)-Datawell.ToInt(data));
      3: data:=inttostr(Datawell.ToInt(lvalue)+1);
      4: data:=inttostr(Datawell.ToInt(lvalue)-1);
      5: data:=inttostr(Datawell.ToInt(lvalue)*Datawell.ToInt(data));
      6: begin
           if data = '0' then data:='1';
           data:=inttostr(trunc(Datawell.ToInt(lvalue)/Datawell.ToInt(data)));
         end;
    end;
  end;
  zdata:=data;
  if zdata = '' then zdata:='0';
  if literal = '@VBUFFER' then
    MUDAnsiCodeReceived('FFFA'+inttostr(Datawell.ToInt(zdata)))
  else if literal = '@HP' then
    MUDAnsiCodeReceived('FFFA'+inttostr(Datawell.ToInt(zdata)))
  else if literal = '@MAXHP' then
    MUDAnsiCodeReceived('FFFB'+inttostr(Datawell.ToInt(zdata)))
  else if literal = '@HPMAX' then
    MUDAnsiCodeReceived('FFFB'+inttostr(Datawell.ToInt(zdata)))
  else if literal = '@SP' then
    MUDAnsiCodeReceived('FFFC'+inttostr(Datawell.ToInt(zdata)))
  else if literal = '@MAXSP' then
    MUDAnsiCodeReceived('FFFD'+inttostr(Datawell.ToInt(zdata)))
  else if literal = '@SPMAX' then
    MUDAnsiCodeReceived('FFFD'+inttostr(Datawell.ToInt(zdata)))
  else if literal = '@GP1' then
    MUDAnsiCodeReceived('FFFE'+inttostr(Datawell.ToInt(zdata)))
  else if literal = '@MAXGP1' then
    MUDAnsiCodeReceived('FFFF'+inttostr(Datawell.ToInt(zdata)))
  else if literal = '@GP1MAX' then
    MUDAnsiCodeReceived('FFFF'+inttostr(Datawell.ToInt(zdata)))
  else if literal = '@GP2' then
    MUDAnsiCodeReceived('FFFG'+inttostr(Datawell.ToInt(zdata)))
  else if literal = '@MAXGP2' then
    MUDAnsiCodeReceived('FFFH'+inttostr(Datawell.ToInt(zdata)))
  else if literal = '@GP2MAX' then
    MUDAnsiCodeReceived('FFFH'+inttostr(Datawell.ToInt(zdata)))
  else if literal = '@ENEMY' then
    MUDAnsiCodeReceived('FFFL'+zdata)
  else if literal = '@ENAME' then
    MUDAnsiCodeReceived('FFFK'+data)
  else if literal = '@CHAT' then
    MUDAnsiCodeReceived('CAA'+data)
  else if literal = '@TELL' then
    MUDAnsiCodeReceived('BAB'+data)
  else if literal = '@GLINE1' then
    SetGLine(data,1)
  else if literal = '@GLINE2' then
    SetGLine(data,2)
  else if literal = '@IMAGE' then
    MUDAnsiCodeReceived('AAB'+data)
  else if literal = '@AVI' then
    MUDAnsiCodeReceived('AAG'+data)
  else if literal = '@SOUND' then
    PlaySound(data,1,1,0,false)
  else if (literal = '@MUSIC') or (literal = '@MIDI') then
    MUDAnsiCodeReceived('AAD'+data)
  else if literal = '@MWCOMBAT' then
    Special(1,data)
  else if literal = '@MWGUILD' then
    Special(2,data)
  else if literal = '@CAPTION' then
    MUDAnsiCodeReceived('CAP'+data)
  else if literal = '@AUTOTYPER' then
    AppendToAutotyper(data)
  else if literal = '@SYSTEM' then
    MUDAnsiFilter(data)
  else if literal = '@EXECUTE' then
    ExecuteExternal(data)
  else begin
    Datawell.UpdateVariable(literal,data);
    UpdateCanvasVariable(literal,data);
  end;
  result:=data;
end;

function TFormMain.DoFunction(data: string): string;
begin
  result:=data;
  if copy(data,1,4) = 'set(' then result:=DoSet(data)
  else if copy(data,1,5) = 'math(' then result:=DoMath(Datawell.ReplaceVariables(data))
  else if copy(data,1,7) = 'random(' then begin
    delete(data,length(data),1);
    data:=Datawell.ReplaceVariables(data);
    result:=inttostr(random(Datawell.ToInt(copy(data,8,99999))));
  end
  else if copy(data,1,4) = 'cap(' then begin
    delete(data,length(data),1);
    data:=Datawell.ReplaceVariables(data);
    result:=uppercase(copy(data,5,1))+copy(data,6,99999);
  end
  else if copy(data,1,4) = 'CAP(' then begin
    delete(data,length(data),1);
    data:=Datawell.ReplaceVariables(data);
    result:=uppercase(copy(data,5,99999));
  end
  else if copy(data,1,3) = 'lc(' then begin
    delete(data,length(data),1);
    data:=Datawell.ReplaceVariables(data);
    result:=lowercase(copy(data,4,99999));
  end
  else if copy(data,1,4) = 'cls(' then begin
    delete(data,length(data),1);
    data:=Datawell.ReplaceVariables(data);
    result:=Datawell.CutLeadingSpaces(copy(data,5,99999));
  end
  else if copy(data,1,4) = 'cts(' then begin
    delete(data,length(data),1);
    data:=Datawell.ReplaceVariables(data);
    result:=Datawell.CutTrailingSpaces(copy(data,5,99999));
  end
  else if copy(data,1,4) = 'cbs(' then begin
    delete(data,length(data),1);
    data:=Datawell.ReplaceVariables(data);
    result:=Datawell.CutTrailingSpaces(copy(data,5,99999));
    result:=Datawell.CutLeadingSpaces(result);
  end
  else if copy(data,1,7) = 'length(' then begin
    delete(data,length(data),1);
    data:=Datawell.ReplaceVariables(data);
    result:=inttostr(length(copy(data,8,99999)));
  end
  else if copy(data,1,5) = 'copy(' then begin
    delete(data,length(data),1);
    data:=Datawell.subs(',',Datawell.specialcode3,data);
    data:=Datawell.ReplaceVariables(data);
    data:=Datawell.subs(',',Datawell.specialcode2,data);
    data:=Datawell.subs(Datawell.specialcode2,'\,',data);
    data:=Datawell.subs(Datawell.specialcode3,',',data);
    result:=DoCopy(copy(data,6,99999),0);
  end
  else if copy(data,1,7) = 'delete(' then begin
    delete(data,length(data),1);
    data:=Datawell.subs(',',Datawell.specialcode3,data);
    data:=Datawell.ReplaceVariables(data);
    data:=Datawell.subs(',',Datawell.specialcode2,data);
    data:=Datawell.subs(Datawell.specialcode2,'\,',data);
    data:=Datawell.subs(Datawell.specialcode3,',',data);
    result:=DoCopy(copy(data,8,99999),1);
  end
  else if copy(data,1,4) = 'pos(' then begin
    delete(data,length(data),1);
    data:=Datawell.subs(',',Datawell.specialcode3,data);
    data:=Datawell.ReplaceVariables(data);
    data:=Datawell.subs(',',Datawell.specialcode2,data);
    data:=Datawell.subs(Datawell.specialcode2,'\,',data);
    data:=Datawell.subs(Datawell.specialcode3,',',data);
    result:=DoPos(copy(data,5,99999));
  end
  else if copy(data,1,4) = 'abs(' then begin
    delete(data,length(data),1);
    data:=Datawell.ReplaceVariables(data);
    result:=inttostr(abs(Datawell.ToInt(copy(data,5,99999))));
  end
  else if copy(data,1,5) = 'subs(' then begin
    delete(data,1,5);
    delete(data,length(data),1);
    data:=Datawell.subs(',',Datawell.specialcode3,data);
    data:=Datawell.ReplaceVariables(data);
    data:=Datawell.subs(',',Datawell.specialcode2,data);
    data:=Datawell.subs(Datawell.specialcode2,'\,',data);
    data:=Datawell.subs(Datawell.specialcode3,',',data);
    result:=DoSubs(data);
  end
  else if copy(data,1,3) = 'dl(' then begin
    delete(data,length(data),1);
    data:=Datawell.ReplaceVariables(data);
    result:=copy(data,5,99999);
  end
  else if copy(data,1,3) = 'dt(' then begin
    delete(data,1,3);
    delete(data,length(data),1);
    data:=Datawell.ReplaceVariables(data);
    delete(data,length(data),1);
    result:=data;
  end
  else if copy(data,1,5) = 'sqrt(' then begin
    delete(data,length(data),1);
    delete(data,1,5);
    data:=Datawell.ReplaceVariables(data);
    result:=inttostr(trunc(sqrt(Datawell.ToInt(data))));
  end
  else if copy(data,1,9) = 'datetime(' then begin
    data:=Datawell.ReplaceVariables(data);
    result:=DoDateTime(data,false);
  end
  else if copy(data,1,4) = 'sum(' then begin
    data:=Datawell.ReplaceVariables(data);
    result:=DoSum(data,false);
  end
  else if copy(data,1,4) = 'avg(' then begin
    data:=Datawell.ReplaceVariables(data);
    result:=DoSum(data,true);
  end
  else if copy(data,1,7) = 'ticker(' then begin
    data:=Datawell.ReplaceVariables(data);
    result:=GetTickerValue(data);
  end
  else if pos('R(',data) > 0 then begin
    data:=Datawell.subs(',',Datawell.specialcode3,data);
    data:=Datawell.ReplaceVariables(data);
    data:=Datawell.subs(',',Datawell.specialcode2,data);
    data:=Datawell.subs(Datawell.specialcode2,'\,',data);
    data:=Datawell.subs(Datawell.specialcode3,',',data);
    result:=RSelect(data);
  end
  else if pos('@(',data) > 0 then begin
    data:=Datawell.subs(',',Datawell.specialcode3,data);
    data:=Datawell.ReplaceVariables(data);
    data:=Datawell.subs(',',Datawell.specialcode2,data);
    data:=Datawell.subs(Datawell.specialcode2,'\,',data);
    data:=Datawell.subs(Datawell.specialcode3,',',data);
    result:=CSelect(data);
  end;
end;

function TFormMain.DoSet(str: string): string;
begin
  delete(str,1,4);
  delete(str,length(str),1);
  result:=Compile(str);
end;

function TFormMain.DoMath(str: string): string;
var
  a, kind, i, x, y, z: integer;
  work: string;
begin
  delete(str,1,5);
  delete(str,length(str),1);
  result:=str;
  a:=pos('+',str);
  if a > 0 then kind:=1
  else begin
    a:=pos('*',str);
    if a > 0 then kind:=2
    else begin
      a:=pos('/',str);
      if a > 0 then kind:=3
      else begin
        a:=pos('%',str);
        if a > 0 then kind:=4
        else begin
          a:=pos('^',str);
          if a > 0 then kind:=5
          else begin
            a:=pos('-',str);
            if a > 0 then kind:=6
            else kind := -1;
          end;
        end;
      end;
    end;
  end;
  case kind of
    1: result:=inttostr(Datawell.ToInt(copy(str,1,a-1))+Datawell.ToInt(copy(str,a+1,99999)));
    2: result:=inttostr(Datawell.ToInt(copy(str,1,a-1))*Datawell.ToInt(copy(str,a+1,99999)));
    3: begin
         work:=copy(str,a+1,99999);
         if (work = '0') or (work = '') then work:='1';
         result:=inttostr(Datawell.ToInt(copy(str,1,a-1)) div Datawell.ToInt(work));
       end;
    4: begin
         work:=copy(str,a+1,99999);
         if (work = '0') or (work = '') then work:='1';
         result:=inttostr(Datawell.ToInt(copy(str,1,a-1)) mod Datawell.ToInt(work));
       end;
    5: begin
         work:=copy(str,a+1,99999);
         if (work = '0') or (work = '') then result:='1'
         else begin
           x:=Datawell.ToInt(copy(str,1,a-1));
           y:=Datawell.ToInt(work);
           z:=x;
           for i:=0 to y-2 do begin
             if x > 9999999 then break;
             x:=x*z;
           end;
           result:=inttostr(x);
         end;
       end;
    6: result:=inttostr(Datawell.ToInt(copy(str,1,a-1))-Datawell.ToInt(copy(str,a+1,99999)));
  end;
end;

function TFormMain.DoDateTime(str: string; dat: boolean): string;
begin
  delete(str,1,9);
  delete(str,length(str),1);
  result:=formatdatetime(str,now);
end;

function TFormMain.DoSum(str: string; average: boolean): string;
var
  i, sum: integer;
  elements: TStringList;
begin
  delete(str,length(str),1);
  delete(str,1,4);
  elements:=TStringList.create;
  Datawell.explode(str,',',elements);
  sum:=0;
  for i:=0 to elements.count-1 do inc(sum,Datawell.ToInt(elements[i]));
  if average then result:=inttostr(trunc(sum/elements.count))
  else result:=inttostr(sum);
  elements.free;
end;

function TFormMain.GetTickerValue(str: string): string;
var
   ticker: TPortalTimestamp;
   id: integer;
begin
   delete(str,length(str),1);
   delete(str,1,7);
   id := StrToIntDef(str, -1);
   result := '';
   if id <> -1 then
      for ticker in FTickers do
         if ticker.TickerID = id then
         begin
            result := IntToStr(round(ticker.timeRemaining / 1000));
            Break;
         end;
   if result = '' then
      result := 'Invalid ticker ID: ' + str;
end;

function TFormMain.DoSubs(str: string): string;
var
  i, j: integer;
  newstr, oldstr, work: string;
begin
  str:=Datawell.subs('\,',Datawell.specialcode,str);
  result:=str;
  i:=pos(',',str);
  if i < 1 then exit;
  oldstr:=copy(str,1,i-1);
  oldstr:=Datawell.subs(Datawell.specialcode,',',oldstr);
  str:=copy(str,i+1,99999);
  j:=pos(',',str);
  if j < 1 then exit;
  newstr:=copy(str,1,j-1);
  newstr:=Datawell.subs(Datawell.specialcode,',',newstr);
  work:=copy(str,j+1,99999);
  work:=Datawell.subs(Datawell.specialcode,',',work);
  result:=Datawell.subs(oldstr,newstr,work);
end;

function TFormMain.DoCopy(str: string; kind: integer): string;
var
  i, j: integer;
  work: string;
begin
  str:=Datawell.subs('\,',Datawell.specialcode,str);
  if kind = 1 then result:=str else result:='';
  i:=pos(',',str);
  if i < 1 then exit;
  work:=copy(str,1,i-1);
  work:=Datawell.subs(Datawell.specialcode,',',work);
  str:=copy(str,i+1,99999);
  str:=Datawell.subs(Datawell.specialcode,',',str);
  j:=pos(',',str);
  if j < 1 then exit;
  i:=Datawell.ToInt(copy(str,1,j-1));
  j:=Datawell.ToInt(copy(str,j+1,99999));
  if kind = 0 then result:=copy(work,i,j)
  else begin
    delete(work,i,j);
    result:=work;
  end;
end;

function TFormMain.DoPos(str: string): string;
var
  i: integer;
  element: string;
begin
  str:=Datawell.subs('\,',Datawell.specialcode,str);
  result:='0';
  i:=pos(',',str);
  if i < 1 then exit;
  element:=copy(str,1,i-1);
  element:=Datawell.subs(Datawell.specialcode,',',element);
  str:=copy(str,i+1,99999);
  str:=Datawell.subs(Datawell.specialcode,',',str);
  i:=pos(element,str);
  result:=inttostr(i);
end;

function TFormMain.CSelect(str: string): string;
var
  i, j: integer;
  value, work: string;
begin
  delete(str,length(str),1);
  i:=pos('@(',str);
  delete(str,1,i+1);
  str:=Datawell.subs('\,',Datawell.specialcode,str);
  i:=pos(':',str);
  if i < 1 then i:=pos(',',str);
  value:=copy(str,1,i-1); delete(str,1,i);
  value:=Datawell.subs(Datawell.specialcode,',',value);
  i:=pos(',',str);
  while i > 0 do begin
    work:=copy(str,1,i-1);
    work:=Datawell.subs(Datawell.specialcode,',',work);
    j:=pos('=',work);
    if copy(work,1,j-1) = value then begin
      result:=copy(work,j+1,99999);
      exit;
    end;
    delete(str,1,i);
    i:=pos(',',str);
  end;
  j:=pos('=',str);
  delete(str,1,j);
  result:=Datawell.subs(Datawell.specialcode,',',str);
end;

function TFormMain.RSelect(str: string): string;
var
  i: integer;
  coms: TStringList;
begin
  result:='';
  delete(str,length(str),1);
  str:=Datawell.subs('\,',Datawell.specialcode,str);
  i:=pos('R(',str);
  delete(str,1,i+1);
  if str = '' then exit;
  coms:=TStringList.create;
  Datawell.Explode(str,',',coms);
  result:=Datawell.subs(Datawell.specialcode,',',coms[random(coms.count)]);
  coms.free;
end;

function TFormMain.ParseLogic(data: string; kind: integer): boolean;
var
  action, elseaction: string;
  i: integer;
begin
  result:=false;
  if copy(data,1,3) <> 'if ' then exit;
  result:=true;
  delete(data,1,3);
  if data = '' then begin
    SystemText('Format is: '+Datawell.TableOptions.fieldbyname('Activator').asstring+
      'if <variable><modifier><value> then <action>',0);
    SystemText('  Example: if $a > 50 then '+Datawell.TableOptions.fieldbyname('Activator').asstring+
      'say it''s above 50!'+Datawell.TableOptions.fieldbyname('Activator').asstring+'grin',0);
    exit;
  end;
  i:=pos(' then ',data);
  if i < 1 then begin
    SystemText('Format is: '+Datawell.TableOptions.fieldbyname('Activator').asstring+
      'if <variable><modifier><value> then <action>',0);
    SystemText('  Example: if $a > 50 then '+Datawell.TableOptions.fieldbyname('Activator').asstring+
      'say it''s above 50!'+Datawell.TableOptions.fieldbyname('Activator').asstring+'grin',0);
    exit;
  end;
  action:=copy(data,i+6,99999);
  delete(data,i,99999);
  elseaction:='';
  i:=pos(' else ',action);
  if i > 0 then begin
    elseaction:=copy(action,i+6,99999);
    delete(action,i,99999);
  end;
  data:=Datawell.ReplaceFunctions(data);
  data:=Datawell.ReplaceVariables(data);
  if Datawell.DoLogic(data) then ParseMain(action,kind)
  else if elseaction <> '' then ParseMain(elseaction,kind);
end;

procedure TFormMain.MUDAnsiLinkClick(target: string);
begin
  if target = '' then exit;
  if not Datawell.TableOptions2.fieldbyname('EnableHyperlinks').asboolean then exit;
  Datawell.EXE(target,'','c:\',SW_SHOW);
end;

procedure TFormMain.MenuSetupToolsClick(Sender: TObject);
var form: TFormTools;
begin
  form:=TFormTools.create(self);
  form.showmodal;
  form.free;
  UpdateTools;
end;

procedure TFormMain.UpdateTools;
var
  tool: boolean;
  mitems, mhints: TStringList;
begin
  mitems:=TStringList.create;
  mhints:=TStringList.create;
  NoTools.visible:=true;
  Tool1.enabled:=false;
  Tool2.enabled:=false;
  Tool3.enabled:=false;
  Tool4.enabled:=false;
  Tool5.enabled:=false;
  Tool6.enabled:=false;
  Tool7.enabled:=false;
  Tool8.enabled:=false;
  Tool9.enabled:=false;
  Tool0.enabled:=false;
  tool:=false;
  with Datawell.TableTools do begin
    first;
    if not EOF then begin
      if fileexists(fieldbyname('Filename').asstring) then begin
        mitems.add(fieldbyname('Tool').asstring);
        mhints.add(fieldbyname('Filename').asstring);
      end;
      next;
      if not EOF then begin
        if fileexists(fieldbyname('Filename').asstring) then begin
          mitems.add(fieldbyname('Tool').asstring);
          mhints.add(fieldbyname('Filename').asstring);
        end;
        next;
        if not EOF then begin
          if fileexists(fieldbyname('Filename').asstring) then begin
            mitems.add(fieldbyname('Tool').asstring);
            mhints.add(fieldbyname('Filename').asstring);
          end;
          next;
          if not EOF then begin
            if fileexists(fieldbyname('Filename').asstring) then begin
              mitems.add(fieldbyname('Tool').asstring);
              mhints.add(fieldbyname('Filename').asstring);
            end;
            next;
            if not EOF then begin
              if fileexists(fieldbyname('Filename').asstring) then begin
                mitems.add(fieldbyname('Tool').asstring);
                mhints.add(fieldbyname('Filename').asstring);
              end;
              next;
              if not EOF then begin
                if fileexists(fieldbyname('Filename').asstring) then begin
                  mitems.add(fieldbyname('Tool').asstring);
                  mhints.add(fieldbyname('Filename').asstring);
                end;
                next;
                if not EOF then begin
                  if fileexists(fieldbyname('Filename').asstring) then begin
                    mitems.add(fieldbyname('Tool').asstring);
                    mhints.add(fieldbyname('Filename').asstring);
                  end;
                  next;
                  if not EOF then begin
                    if fileexists(fieldbyname('Filename').asstring) then begin
                      mitems.add(fieldbyname('Tool').asstring);
                      mhints.add(fieldbyname('Filename').asstring);
                    end;
                    next;
                    if not EOF then begin
                      if fileexists(fieldbyname('Filename').asstring) then begin
                        mitems.add(fieldbyname('Tool').asstring);
                        mhints.add(fieldbyname('Filename').asstring);
                      end;
                      next;
                      if not EOF then begin
                        if fileexists(fieldbyname('Filename').asstring) then begin
                          mitems.add(fieldbyname('Tool').asstring);
                          mhints.add(fieldbyname('Filename').asstring);
                        end;
                      end;
                    end;
                  end;
                end;
              end;
            end;
          end;
        end;
      end;
    end;
  end;
  if mitems.count > 0 then begin
    Tool1.caption:='&1  '+mitems[0]; Tool1.hint:=mhints[0];
    mitems.delete(0); mhints.delete(0);
    Tool1.enabled:=true; tool:=true;
    if mitems.count > 0 then begin
      Tool2.caption:='&2  '+mitems[0]; Tool2.hint:=mhints[0];
      mitems.delete(0); mhints.delete(0);
      Tool2.enabled:=true; tool:=true;
      if mitems.count > 0 then begin
        Tool3.caption:='&3  '+mitems[0]; Tool3.hint:=mhints[0];
        mitems.delete(0); mhints.delete(0);
        Tool3.enabled:=true; tool:=true;
        if mitems.count > 0 then begin
          Tool4.caption:='&4  '+mitems[0]; Tool4.hint:=mhints[0];
          mitems.delete(0); mhints.delete(0);
          Tool4.enabled:=true; tool:=true;
          if mitems.count > 0 then begin
            Tool5.caption:='&5  '+mitems[0]; Tool5.hint:=mhints[0];
            mitems.delete(0); mhints.delete(0);
            Tool5.enabled:=true; tool:=true;
            if mitems.count > 0 then begin
              Tool6.caption:='&6  '+mitems[0]; Tool6.hint:=mhints[0];
              mitems.delete(0); mhints.delete(0);
              Tool6.enabled:=true; tool:=true;
              if mitems.count > 0 then begin
                Tool7.caption:='&7  '+mitems[0]; Tool7.hint:=mhints[0];
                mitems.delete(0); mhints.delete(0);
                Tool7.enabled:=true; tool:=true;
                if mitems.count > 0 then begin
                  Tool8.caption:='&8  '+mitems[0]; Tool8.hint:=mhints[0];
                  mitems.delete(0); mhints.delete(0);
                  Tool8.enabled:=true; tool:=true;
                  if mitems.count > 0 then begin
                    Tool9.caption:='&9  '+mitems[0]; Tool9.hint:=mhints[0];
                    mitems.delete(0); mhints.delete(0);
                    Tool9.enabled:=true; tool:=true;
                    if mitems.count > 0 then begin
                      Tool0.caption:='&0  '+mitems[0]; Tool0.hint:=mhints[0];
                      mitems.delete(0); mhints.delete(0);
                      Tool0.enabled:=true; tool:=true;
                    end;
                  end;
                end;
              end;
            end;
          end;
        end;
      end;
    end;
  end;
  if tool then NoTools.visible:=false;
  Tool1.visible:=Tool1.enabled;
  Tool2.visible:=Tool2.enabled;
  Tool3.visible:=Tool3.enabled;
  Tool4.visible:=Tool4.enabled;
  Tool5.visible:=Tool5.enabled;
  Tool6.visible:=Tool6.enabled;
  Tool7.visible:=Tool7.enabled;
  Tool8.visible:=Tool8.enabled;
  Tool9.visible:=Tool9.enabled;
  Tool0.visible:=Tool0.enabled;
  mitems.free;
  mhints.free;
end;

procedure TFormMain.Tool1Click(Sender: TObject);
var filename: string;
begin
  filename:=TMenuItem(sender).hint;
  if filename = '' then exit;
  if not fileexists(filename) then exit;
  ShellExecute(self.handle,nil,pchar(filename),nil,nil,sw_shownormal);
end;

procedure TFormMain.MenuLiteralClick(Sender: TObject);
var key: char;
begin
  key:=#13;
  shifting:=true;
  EditSendKeyPress(sender,key);
  shifting:=false;
end;

procedure TFormMain.CtrlA1Click(Sender: TObject);
var c: string;
begin
  c:=#1;
  case TMenuItem(sender).tag of
     2: c:=#2;
     3: c:=#3;
     4: c:=#4;
     5: c:=#5;
     6: c:=#6;
     7: c:=#7;
     8: c:=#8;
     9: c:=#9;
    10: c:=#10;
    11: c:=#11;
    12: c:=#12;
    13: c:=#13;
    14: c:=#14;
    15: c:=#15;
    16: c:=#16;
    17: c:=#17;
    18: c:=#18;
    19: c:=#19;
    20: c:=#20;
    21: c:=#21;
    22: c:=#22;
    23: c:=#23;
    24: c:=#24;
    25: c:=#25;
    26: c:=#26;
  end;
  MemoCopy.text:=c;
  MemoPaste.lines.clear;
  MemoPaste.pastefromclipboard;
  MemoCopy.selectall;
  MemoCopy.copytoclipboard;
  EditSend.pastefromclipboard;
  MemoPaste.selectall;
  MemoPaste.copytoclipboard;
end;

procedure TFormMain.BtnUpOneClick(Sender: TObject);
begin
  case TComponent(sender).tag of
    -1 : ScrollUp(1);
     1 : ScrollDown(1);
  end;
end;

procedure TFormMain.TimerGrabDataTimer(Sender: TObject);
begin
  Datawell.ringed:=true;
  TimerGrabData.enabled:=false;
  if Datawell.abortdata then exit;
end;

procedure TFormMain.BtnCloseSendsClick(Sender: TObject);
begin
  PanelSends.hide;
end;

procedure TFormMain.BtnShowSendsClick(Sender: TObject);
var
  i: integer;
  work: string;
begin
  if PanelSends.visible then begin
    PanelSends.hide;
    exit;
  end;
  if Sends.count < 1 then exit;
  MemoSends.lines.clear;
  for i:=0 to Sends.count-1 do begin
    work:=Sends[i];
    if copy(work,1,3) = '|P|' then delete(work,1,3) else work:=copy(work,7,99999);
    if copy(work,1,length(Datawell.specialcode2)) = Datawell.specialcode2 then
      delete(work,1,length(Datawell.specialcode2));
    MemoSends.lines.add(inttostr(i+1)+') '+work);
  end;
  PanelSends.show;
  if visible then EditSend.setfocus;
end;

procedure TFormMain.UpdateRecordbar;
begin
  if MenuShowRecordTool.checked then begin
    PanelRecordBase.width:=194;
    BtnCloseToolbar.left:=179;
    PanelRecord.show;
  end
  else begin
    PanelRecordBase.width:=15;
    BtnCloseToolbar.left:=0;
    PanelRecord.hide;
  end;
end;

procedure TFormMain.MenuShowRecordToolClick(Sender: TObject);
begin
  if recording then begin
    messagedlg('Recording',mtinformation,[mbok],0);
    exit;
  end;
  MenuShowRecordTool.checked:= not MenuShowRecordTool.checked;
  UpdateRecordbar;
end;

function TFormMain.ParseSprint(data: string): boolean;
var
  x, y, p, sprintresult: integer;
  map: string;
  zzz: TStringList;
begin
  result:=false;
  x:=-888888; y:=-888888; map:=FormMap.CMAP;
  if copy(data,1,7) <> 'sprint ' then exit;
  result:=true;
  if DoDelaying(data) then exit;
  delete(data,1,7);
  if FormMap.BtnChart.down then begin
    systemtext('You cannot sprint while charting',0);
    exit;
  end;
  p:=pos(',',data);
  if p > 0 then begin
    x:=Datawell.toint(copy(data,1,p-1));
    delete(data,1,p);
    p:=pos(',',data);
    if p > 0 then begin
      y:=Datawell.toint(copy(data,1,p-1));
      map:=copy(data,p+1,9999);
      map:=uppercase(map);
      if not Datawell.IsMap(map) then begin
        systemtext('Map: ['+map+'] does not exist',0);
        exit;
      end;
    end
    else y:=Datawell.toint(data);
  end;
  if (x = -888888) or (y = -888888) then begin
    systemtext('Format is: "'+Datawell.TableOptions.fieldbyname('Activator').asstring+
      'sprint x,y" or "'+Datawell.TableOptions.fieldbyname('Activator').asstring+
      'sprint x,y,map"',0);
    exit;
  end;
  if (x = FormMap.CX) and (y = FormMap.CY) and
    (map = FormMap.CMAP) then begin
    systemtext('That''s the same room - duh',0);
    exit;
  end;
  systemtext('Sprint to: ('+inttostr(x)+','+inttostr(y)+') on map level ['+map+']',0);
  zzz:=TStringList.create;
  sprintresult:=FormMap.Sprint(map,x,y,false,zzz);
  zzz.free;
  case sprintresult of
    -1: systemtext('No link exists to that room',0);
     0: systemtext('No path found',0);
  end;
end;

function TFormMain.ParseChartingRoom(work: string): boolean;
var
  rform: TFormRProperties;
  x1, y1, r1, r2, r3: integer;
  map, ss1, s1, s2, s3, ch: string;
  doroom1: boolean;
begin
  result:=true;
  if copy(work,1,1) <> ' ' then begin
    rform:=TFormRProperties.create(self);
    if rform.LoadOptions(FormMap.CMAP,FormMap.CX,FormMap.CY,false) then begin
      rform.showmodal;
    end
    else systemtext('No room exists at('+inttostr(FormMap.CX)+','+
      inttostr(FormMap.CY)+') ['+FormMap.CMAP+']',0);
    rform.free;
    FormMap.UpdateFilters(FormMap.CMAP);
    FormMap.DrawMap(false);
    exit;
  end;
  delete(work,1,1);
  x1:=FormMap.CX;
  y1:=FormMap.CY;
  if (work = 'add') or (work = 'a') then begin
    map:=FormMap.CMAP;
    r1:=FormMap.FigureRoom;
    r2:=Datawell.FigureColor(FormMap.ColorGrid.foregroundindex);
    r3:=Datawell.FigureColor(FormMap.ColorGrid.backgroundindex);
    s1:=''; s2:=''; s3:=''; ss1:='';
    doroom1:=FormMap.RoomProperties(map,x1,y1,r1,r2,r3,s1,s2,s3,ss1);
    FormMap.CreateRoom(map,x1,y1,FormMap.FigureRoom,
      Datawell.FigureColor(FormMap.ColorGrid.foregroundindex),
      Datawell.FigureColor(FormMap.ColorGrid.backgroundindex),
      '','','','',true);
    if doroom1 then
      systemtext('Room ('+inttostr(x1)+','+inttostr(y1)+') ['+map+'] replaced',0)
    else
      systemtext('Room ('+inttostr(x1)+','+inttostr(y1)+') ['+map+'] created',0);
    FormMap.DrawMap(false);
  end
  else if (work = 'delete') or (work = 'd') then begin
    map:=FormMap.CMAP;
    if FormMap.DeleteRoom(map,x1,y1,false,true) then
      systemtext('Room ('+inttostr(x1)+','+inttostr(y1)+') ['+map+'] deleted',0)
    else
      systemtext('No room exists at ('+inttostr(x1)+','+inttostr(y1)+') ['+map+']',0);
    FormMap.DrawMap(false);
  end
  else if (work = 'delete all') or (work = 'da') then begin
    map:=FormMap.CMAP;
    if FormMap.DeleteRoom(map,x1,y1,true,true) then
      systemtext('Room ('+inttostr(x1)+','+inttostr(y1)+') ['+map+'] and exits deleted',0)
    else
      systemtext('No room exists at ('+inttostr(x1)+','+inttostr(y1)+') ['+map+']',0);
    FormMap.DrawMap(false);
  end
  else if (copy(work,1,7) = 'refresh') or (copy(work,1,1) = 'r') then begin
    if copy(work,1,7) = 'refresh' then delete(work,2,6);
    delete(work,1,1);
    if copy(work,1,1) = ' ' then delete(work,1,1);
    if work = '' then work:=Datawell.TableGlobals.fieldbyname('S1').asstring;
    if work = '' then work:='look';
    if FormMap.RoomAt(FormMap.CMAP,FormMap.CX,FormMap.CY) then begin
      map:=FormMap.CMAP;
      systemtext('Refreshing room ('+inttostr(x1)+','+inttostr(y1)+') ['+map+']',0);
      r1:=FormMap.FigureRoom;
      r2:=Datawell.FigureColor(FormMap.ColorGrid.foregroundindex);
      r3:=Datawell.FigureColor(FormMap.ColorGrid.backgroundindex);
      s1:=''; s2:=''; s3:=''; ss1:='';
      FormMap.gmap2:=map;
      FormMap.x2:=x1;
      FormMap.y2:=y1;
      FormMap.r4:=r1;
      FormMap.r5:=r2;
      FormMap.r6:=r3;
      FormMap.s4:=s1;
      FormMap.s5:=s2;
      FormMap.s6:=s3;
      FormMap.room2:=true;
      FormMap.LabelClock.caption:=
        inttostr(Datawell.TableGlobals.fieldbyname('FailureTimer').asinteger);
      FormMap.LabelClock.font.color:=clwhite;
      FormMap.LabelClock.color:=clred;
      FormMap.TimerCountdown.enabled:=false;
      FormMap.TimerCountdown.enabled:=true;
      FormMap.awaitingfailure:=true;
      FormMap.refreshingroom:=true;
      SetupEvents;
      ParseMain(work,1);
    end
    else
      systemtext('No room exists at ('+inttostr(x1)+','+inttostr(y1)+') ['+map+']',0);
    FormMap.DrawMap(false);
  end
  else systemtext('Format is "'+ch+'room" "'+ch+'room add" "'+
    ch+'room delete" "'+ch+'room delete all"',0);
end;

function TFormMain.ParseChartingLabelTag(work, ch: string): boolean;
var
  tagged: string;
  didfind: boolean;
begin
  result:=true;
  if copy(work,1,4) = ch+'tag' then begin
    delete(work,1,5);
    if length(work) > 1 then begin
      systemtext('A room tag can only be one character',0);
      exit;
    end;
    tagged:='tag';
  end
  else begin
    delete(work,1,6);
    if length(work) > 255 then begin
      systemtext('A room label can only be 255 characters long',0);
      exit;
    end;
    tagged:='label';
  end;
  didfind:=false;
  with Datawell.TableRooms do begin
    first;
    while not EOF do begin
      if (Datawell.TableRooms.fieldbyname('X').asinteger = FormMap.CX) and
        (Datawell.TableRooms.fieldbyname('Y').asinteger = FormMap.CY) then begin
        didfind:=true;
        break;
      end;
      next;
    end;
    if didfind then begin
      edit;
      if tagged = 'tag' then Datawell.TableRooms.fieldbyname('Tag').asstring:=work
      else Datawell.TableRooms.fieldbyname('Label').asstring:=work;
      post;
      if work = '' then systemtext('Room ('+inttostr(FormMap.CX)+','+
        inttostr(FormMap.CY)+') '+tagged+' cleared',0)
      else systemtext('Room ('+inttostr(FormMap.CX)+','+
        inttostr(FormMap.CY)+') '+tagged+' set to: '+work,0)
    end
    else systemtext('No room exists at ('+inttostr(FormMap.CX)+','+
      inttostr(FormMap.CY)+')',0);
  end;
  FormMap.DrawMap(false);
end;

function TFormMain.parseChartingStubs(const work: string): boolean;
var
  didfind: boolean;
  ss1, ss2: string;
  i, p: integer;
begin
  result:=true;
  if (length(work) < 1) or (length(work) > 9) then begin
    systemtext('The room stubs string must be from 1-9 characters long',0);
    exit;
  end;
  didfind:=true;
  ss2:='123456789';
  for i:=1 to length(work) do begin
    ss1:=copy(work,i,1);
    if (ss1 <> '1') and (ss1 <> '2') and (ss1 <> '3') and
       (ss1 <> '4') and (ss1 <> '5') and (ss1 <> '6') and
       (ss1 <> '7') and (ss1 <> '8') and (ss1 <> '9') then didfind:=false;
    p:=pos(ss1,ss2);
    if p > 0 then delete(ss2,p,1)
    else didfind:=false;
  end;
  if not didfind then begin
    systemtext('Room stubs must be from 1 to 9, and cannot be doubled-up',0);
    exit;
  end;
  didfind:=false;
  with Datawell.TableRooms do begin
    first;
    while not EOF do begin
      if (Datawell.TableRooms.fieldbyname('X').asinteger = FormMap.CX) and
        (Datawell.TableRooms.fieldbyname('Y').asinteger = FormMap.CY) then begin
        didfind:=true;
        break;
      end;
      next;
    end;
    if didfind then begin
      edit;
      Datawell.TableRooms.fieldbyname('Stubs').asstring:=work;
      post;
      systemtext('Room ('+inttostr(FormMap.CX)+','+
        inttostr(FormMap.CY)+') stubs set to: '+work,0)
    end
    else systemtext('No room exists at ('+inttostr(FormMap.CX)+','+
      inttostr(FormMap.CY)+')',0);
  end;
  FormMap.DrawMap(false);
end;

function TFormMain.parseChartingChart(work: string; var kind: integer): boolean;
var
  p, x1, y1: integer;
  map: string;
begin
  if work = '' then begin
    FormMap.BtnChart.down:=not FormMap.BtnChart.down;
    FormMap.BtnChart.click;
    exit(true);
  end;
  if copy(work,1,1) <> ' ' then exit(false);
  delete(work,1,1);
  if FormMap.TryCurrentExit(work) then
    exit(true);
  p:=pos(',',work);
  if p > 0 then begin
    x1:=Datawell.toint(copy(work,1,p-1));
    delete(work,1,p);
    p:=pos(',',work);
    if p > 0 then begin
      y1:=Datawell.toint(copy(work,1,p-1));
      map:=copy(work,p+1,9999);
      map:=uppercase(map);
      if not Datawell.IsMap(map) then begin
        systemtext('Map: ['+map+'] does not exist',0);
        result:=true;
        exit;
      end;
    end
    else y1:=Datawell.toint(work);
    FormMap.SetXY(map,x1,y1);
    systemtext('Map location set to: ('+inttostr(x1)+','+inttostr(y1)+
      ') ['+map+']',0);
    result:=true;
    exit;
  end;
  if not FormMap.BtnChart.down then begin
    systemtext('No exit <'+work+'> exists - '+
      'you must be in Charting mode to chart a new exit',0);
    result:=true;
    exit;
  end;
  kind:=999;
  result := false;
end;

function TFormMain.ParseCharting(const dir: string; okind: integer): boolean;
var
  kind, x1, y1, x2, y2, r1, r2, r3, r4, r5, r6, lcol: integer;
  work, link1, link2, ch, map, map1, map2, s1, s2, s3, s4, s5, s6, ss1, ss2: string;
  p1, p2, p3, p4, rev, ab: string;
  linked, doroom1, doroom2: boolean;

  function ParseChartingCreateLink(): boolean;
  var
    form: TFormConfirmLink;
  begin
    form:=TFormConfirmLink.create(self);
    try
      case r1 of
        0: form.b0.down:=true;
        1: form.b1.down:=true;
        2: form.b2.down:=true;
        3: form.b3.down:=true;
        4: form.b4.down:=true;
      end;
      case r4 of
        0: form.c0.down:=true;
        1: form.c1.down:=true;
        2: form.c2.down:=true;
        3: form.c3.down:=true;
        4: form.c4.down:=true;
      end;
      form.ColorLink.foregroundindex:=FormMap.ColorGrid.foregroundindex;
      form.Colors1.foregroundindex:=Datawell.ColorFigure(r2);
      form.Colors1.backgroundindex:=Datawell.ColorFigure(r3);
      form.Colors2.foregroundindex:=Datawell.ColorFigure(r5);
      form.Colors2.backgroundindex:=Datawell.ColorFigure(r6);
      form.Edit1.text:=link1;
      form.Edit2.text:=link2;
      form.EditMap1.text:=map1;
      form.X1.value:=x1;
      form.Y1.value:=y1;
      form.EditMap2.text:=map2;
      form.X2.value:=x2;
      form.Y2.value:=y2;
      form.EditPre1.text:=p1;
      form.EditPost1.text:=p2;
      form.EditPre2.text:=p3;
      form.EditPost2.text:=p4;
      form.UpdateEnabling;
      form.showmodal;
      map1:=form.EditMap1.text;
      map2:=form.EditMap2.text;
      link1:=form.Edit1.text;
      link2:=form.Edit2.text;
      p1:=form.EditPre1.text;
      p2:=form.EditPost1.text;
      p3:=form.EditPre2.text;
      p4:=form.EditPost2.text;
      if form.CheckO.enabled then begin
        doroom1:=form.CheckO.checked;
        r1:=form.FigureRoom(1);
        r2:=Datawell.FigureColor(form.Colors1.ForegroundIndex);
        r3:=Datawell.FigureColor(form.Colors1.BackgroundIndex);
      end;
      if form.CheckD.enabled then begin
        doroom2:=form.CheckD.checked;
        r4:=form.FigureRoom(2);
        r5:=Datawell.FigureColor(form.Colors2.ForegroundIndex);
        r6:=Datawell.FigureColor(form.Colors2.BackgroundIndex);
      end;
      lcol:=Datawell.FigureColor(form.ColorLink.foregroundindex);
      x1:=trunc(form.X1.value);
      y1:=trunc(form.Y1.value);
      x2:=trunc(form.X2.value);
      y2:=trunc(form.Y2.value);
      result := form.linked;
    finally
      form.free;
    end;
  end;

begin
  work:=dir;
  kind:=0;
  x1:=0; x2:=0; map:=FormMap.CMAP;
  result:=false;
  ch:=Datawell.TableOptions.fieldbyname('Activator').asstring;
  //;abortchart command
  if work = ch+'abortchart' then begin
    if not FormMap.awaitingfailure then
      systemtext('No chart to abort',0)
    else FormMap.AbortChart;
    Exit(true);
  end;
  if FormMap.awaitingfailure then begin
    if work = '' then begin
      FormMap.FinalizeLink(true);
      Exit(true);
    end;
    if FormMap.IsCardinal(work) then FormMap.FinalizeLink(true);
    if not FormMap.refreshingroom then begin
      systemtext('Please wait for the current failure check to consummate',0);
      Exit(true);
    end;
  end;
  //;room command
  if copy(work,1,5) = ch+'room' then
     Exit(ParseChartingRoom(copy(work, 6)));
  //;label & ;tag commands
  if (copy(work,1,6) = ch+'label') or (copy(work,1,4) = ch+'tag') then
     Exit(ParseChartingLabelTag(work, ch));
  //;follow command
  if work = ch+'follow' then begin
    FormMap.BtnFollow.down:=not FormMap.BtnFollow.down;
    FormMap.BtnFollow.click;
    result:=true;
    exit;
  end;
  //;stubs command
  if copy(work,1,6) = ch+'stubs' then
    Exit(parseChartingStubs(copy(work, 8)));
  //;mapundo command
  if work = ch+'mapundo' then begin
    FormMap.MenuUndo.click;
    result:=true;
    exit;
  end;
  //;chart command
  if copy(work,1,6) = ch+'chart' then
    Exit(ParseChartingChart(copy(work, 7), kind));
  if controlling then begin
    FormMap.MoveXY(work);
    result:=true;
    exit;
  end;
  if FormMap.BtnFollow.down then begin
    FormMap.TryCurrentExit(work);
    exit;
  end;
  if not FormMap.BtnChart.down then exit;
  if copy(work,1,1) = ch then begin
    delete(work,1,1);
    if FormMap.IsCardinal(work) then begin
      result:=false;
      if FormMap.MenuTextChart.checked then
        systemtext('Forcing a movement : '+work,0);
      exit;
    end;
  end;
  if FormMap.TryCurrentExit(work) then exit;
  if (work = Datawell.Dir('n')) or (work = Datawell.Dir('north')) then kind:=8
  else if (work = Datawell.Dir('e')) or (work = Datawell.Dir('east')) then kind:=6
  else if (work = Datawell.Dir('s')) or (work = Datawell.Dir('south')) then kind:=2
  else if (work = Datawell.Dir('w')) or (work = Datawell.Dir('west')) then kind:=4
  else if (work = Datawell.Dir('ne')) or (work = Datawell.Dir('northeast')) then kind:=9
  else if (work = Datawell.Dir('se')) or (work = Datawell.Dir('southeast')) then kind:=3
  else if (work = Datawell.Dir('sw')) or (work = Datawell.Dir('southwest')) then kind:=1
  else if (work = Datawell.Dir('nw')) or (work = Datawell.Dir('northwest')) then kind:=7
  else if (work = Datawell.Dir('u')) or (work = Datawell.Dir('up')) then kind:=111
  else if (work = Datawell.Dir('d')) or (work = Datawell.Dir('down')) then kind:=222;
  if kind < 1 then exit;
  x1:=FormMap.CX;
  y1:=FormMap.CY;
  x2:=x1;
  y2:=y1;
  case kind of
    9: begin
         inc(x2);
         inc(y2);
       end;
    3: begin
         inc(x2);
         dec(y2);
       end;
    1: begin
         dec(x2);
         dec(y2);
       end;
    7: begin
         dec(x2);
         inc(y2);
       end;
    8: inc(y2);
    6: inc(x2);
    2: dec(y2);
    4: dec(x2);
  end;
  map1:=FormMap.CMAP;
  map2:=map1;
  link1:=work;
  rev:=Datawell.Reverse(work);
  if rev <> '' then link2:=rev
  else link2:=FormMap.OppositeDir(work);
  doroom1:=true;
  doroom2:=true;
  lcol:=Datawell.FigureColor(FormMap.ColorGrid.foregroundindex);
  //Set properties of endpoint rooms
  r1:=FormMap.FigureRoom;
  r2:=Datawell.FigureColor(FormMap.ColorGrid.foregroundindex);
  r3:=Datawell.FigureColor(FormMap.ColorGrid.backgroundindex);
  s1:=''; s2:=''; s3:=''; ss1:='';
  FormMap.RoomProperties(map1,x1,y1,r1,r2,r3,s1,s2,s3,ss1);
  r4:=FormMap.FigureRoom;
  r5:=Datawell.FigureColor(FormMap.ColorGrid.foregroundindex);
  r6:=Datawell.FigureColor(FormMap.ColorGrid.backgroundindex);
  s4:=''; s5:=''; s6:=''; ss2:='';
  FormMap.RoomProperties(map2,x2,y2,r4,r5,r6,s4,s5,s6,ss2);
  p1:=''; p2:=''; p3:=''; p4:='';
  //Set the rooms for up...
  if kind = 111 then begin
    if r1 = 0 then r1:=1
    else if r1 = 2 then r1:=3;
    if r4 = 0 then r4:=2
    else if r4 = 1 then r4:=3;
    ab:=FormMap.FigureAB(map1,'a');
    if ab <> '' then map2:=ab;
  end
  //...and down
  else if kind = 222 then begin
    if r1 = 0 then r1:=2
    else if r1 = 1 then r1:=3;
    if r4 = 0 then r4:=1
    else if r4 = 2 then r4:=3;
    ab:=FormMap.FigureAB(map1,'b');
    if ab <> '' then map2:=ab;
  end
  else if kind = 999 then begin
    r1:=4;
    r4:=4;
  end;
  if (not FormMap.MenuSpeedChart.checked) or (kind = 999) or (kind = 111) or (kind = 222) then begin
    linked := ParseChartingCreateLink;
    if not linked then begin
      result:=true;
      exit
    end;
  end;
  if FormMap.MenuFreeChart.checked then begin
    inc(FormMap.undoid);
    FormMap.overrideroom:=true;
    if doroom1 then FormMap.CreateRoom(map1,x1,y1,r1,r2,r3,s1,s2,s3,ss1,true);
    if doroom2 then FormMap.CreateRoom(map2,x2,y2,r4,r5,r6,s4,s5,s6,ss2,true);
    FormMap.CreateLinkExits(map1,map2,link1,link2,p1,p2,p3,p4,x1,y1,x2,y2,lcol,true);
    FormMap.overrideroom:=false;
    //Check for attic/basement
    FormMap.CheckBasement(map1,map2,link1,link2);
    FormMap.SetXY(FormMap.CMAP,x2,y2);
    FormMap.DrawMap(false);
    FormMap.UpdateFilters(map1);
  end
  else begin
    FormMap.gmap1:=map1;
    FormMap.x1:=x1;
    FormMap.y1:=y1;
    FormMap.gmap2:=map2;
    FormMap.x2:=x2;
    FormMap.y2:=y2;
    FormMap.r1:=r1;
    FormMap.r2:=r2;
    FormMap.r3:=r3;
    FormMap.s1:=s1;
    FormMap.s2:=s2;
    FormMap.s3:=s3;
    FormMap.r4:=r4;
    FormMap.r5:=r5;
    FormMap.r6:=r6;
    FormMap.s4:=s4;
    FormMap.s5:=s5;
    FormMap.s6:=s6;
    FormMap.p1:=p1;
    FormMap.p2:=p2;
    FormMap.p3:=p3;
    FormMap.p4:=p4;
    FormMap.ss1:=ss1;
    FormMap.ss2:=ss2;
    FormMap.link1:=link1;
    FormMap.link2:=link2;
    FormMap.lcol:=lcol;
    if doroom1 then FormMap.room1:=true
    else FormMap.room1:=false;
    if doroom2 then FormMap.room2:=true
    else FormMap.room2:=false;
    FormMap.LabelClock.caption:=
      inttostr(Datawell.TableGlobals.fieldbyname('FailureTimer').asinteger);
    FormMap.LabelClock.font.color:=clwhite;
    FormMap.LabelClock.color:=clred;
    FormMap.TimerCountdown.enabled:=false;
    FormMap.TimerCountdown.enabled:=true;
    FormMap.awaitingfailure:=true;
    SetupEvents;
  end;
  result:=true;
  SendData(work,okind);
end;

procedure TFormMain.TimerHistoryTimer(Sender: TObject);
begin
  ClearHistoryVars;
  if EditSend.text = EditSend.seltext then EditSend.text:='';
  if HistorySearch <> '' then begin
    bypass:=true;
    EditSend.text:=HistorySearch;
    bypass:=false;
    if Datawell.TableOptions.fieldbyname('HighlightKeyhistory').asboolean then EditSend.selectall
    else EditSend.selstart:=length(EditSend.text);
  end;
  HistorySearch:='';
end;

procedure TFormMain.TimerHistory2Timer(Sender: TObject);
begin
  CloseHistory;
  if EditSend.text = EditSend.seltext then EditSend.text:='';
end;

procedure TFormMain.MenuInsertLineBreakClick(Sender: TObject);
var
  p: integer;
  pre, post: string;
begin
  p:=EditSend.selstart;
  pre:=copy(EditSend.text,1,p);
  post:=copy(EditSend.text,p+1,9999);
  EditSend.lines.clear;
  EditSend.lines.add(pre);
  EditSend.lines.add(post);
  EditSend.text:=copy(EditSend.text,1,length(EditSend.text)-2);
  EditSend.setfocus;
  EditSend.selstart:=p+2;
end;

procedure TFormMain.PanelAnnounceClick(Sender: TObject);
begin
  Datawell.EXE(LabelMessage.hint,'','c:\',SW_SHOW);
end;

procedure TFormMain.MenuHPBarClick(Sender: TObject);
var
  form: TFormHP;
  str: string;
  amt, highorder, p: integer;
  table: TClientDataset;
begin
  amt:=0;
  highorder:=0;
  table:=TClientDataset.create(self);
  try
    table.CloneCursor(Datawell.TableEvents, false, true);
    table.filtered := true;
    table.active:=true;
    table.first;
    while not table.EOF do begin
      inc(amt);
      if table.fieldbyname('FOrder').asinteger > highorder then
        highorder:=table.fieldbyname('FOrder').asinteger;
      table.next;
    end;
  finally
     table.free;
  end;
  inc(highorder);
  if amt > 25 then begin
    messagedlg('You can only have 25 events defined for the BASE group.'+#13+
      'You must delete one from that group before you can use the HP Bar Setup Assistant',
    mtinformation,[mbok],0);
    exit;
  end;
  str:=MUDAnsi.selectedtext;
  if str > '' then begin
    p:=pos(#10,str);
    if p > 0 then str:=copy(str,1,p-2);
    while ord(str[length(str)]) < 32 do delete(str,length(Str),1);
  end;
  form:=TFormHP.create(self);
  form.EditPaste.text:=str;
  form.highorder:=highorder;
  form.showmodal;
  form.free;
  SetupEvents;
end;

procedure TFormMain.MenuTelnetClick(Sender: TObject);
begin
  Datawell.EXE('telnet','','c:\',SW_SHOW);
end;

function TFormMain.GetEName: string;
begin
  result:=ImageEnemyName.hint;
end;

procedure TFormMain.ExternalParse(str: string; kind: integer);
begin
  ParseMain(str,kind);
end;

procedure TFormMain.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  if (Datawell.datachecking) and (EditSend.text <> 'X') then canclose:=false;
end;

procedure TFormMain.DoAnimation;
begin
  case animate of
    0: begin
         if animes[0] then begin
           ihp1.hide;
           ihp2.show;
           ihp3.hide;
         end;
         if animes[1] then begin
           isp1.hide;
           isp2.show;
           isp3.hide;
         end;
         if animes[2] then begin
           igp11.hide;
           igp12.show;
           igp13.hide;
         end;
         if animes[3] then begin
           igp21.hide;
           igp22.show;
           igp23.hide;
         end;
       end;
    1: begin
         if animes[0] then begin
           ihp1.hide;
           ihp2.hide;
           ihp3.show;
         end;
         if animes[1] then begin
           isp1.hide;
           isp2.hide;
           isp3.show;
         end;
         if animes[2] then begin
           igp11.hide;
           igp12.hide;
           igp13.show;
         end;
         if animes[3] then begin
           igp21.hide;
           igp22.hide;
           igp23.show;
         end;
       end;
    2: begin
         if animes[0] then begin
           ihp1.hide;
           ihp2.show;
           ihp3.hide;
         end;
         if animes[1] then begin
           isp1.hide;
           isp2.show;
           isp3.hide;
         end;
         if animes[2] then begin
           igp11.hide;
           igp12.show;
           igp13.hide;
         end;
         if animes[3] then begin
           igp21.hide;
           igp22.show;
           igp23.hide;
         end;
       end;
    3: begin
         if animes[0] then begin
           ihp1.show;
           ihp2.hide;
           ihp3.hide;
         end;
         if animes[1] then begin
           isp1.show;
           isp2.hide;
           isp3.hide;
         end;
         if animes[2] then begin
           igp11.show;
           igp12.hide;
           igp13.hide;
         end;
         if animes[3] then begin
           igp21.show;
           igp22.hide;
           igp23.hide;
         end;
       end;
  end;
  inc(animate);
  if animate > 3 then animate:=0;
end;

procedure TFormMain.TimerHPTimer(Sender: TObject);
begin
  TTimer(sender).enabled:=false;
  case TTimer(sender).tag of
    1: begin
         animes[0]:=false;
         ihp1.show;
         ihp2.hide;
         ihp3.hide;
       end;
    2: begin
         animes[1]:=false;
         isp1.show;
         isp2.hide;
         isp3.hide;
       end;
    3: begin
         animes[2]:=false;
         igp11.show;
         igp12.hide;
         igp13.hide;
       end;
    4: begin
         animes[3]:=false;
         igp21.show;
         igp22.hide;
         igp23.hide;
       end;
  end;
end;

procedure TFormMain.Special(stag: integer; str: string);
var
  slabel: TLabel;
  spanel: TPanel;
  stimer: TTimer;
  scol: integer;
begin
  case stag of
    1: begin
         slabel:=LabelSpecial;
         stimer:=TimerSpecial;
         spanel:=PanelSpecial;
         scol:=Datawell.TableOptions.fieldbyname('Color21').asinteger;
       end;
    2: begin
         slabel:=LabelSpecial2;
         stimer:=TimerSpecial2;
         spanel:=PanelSpecial2;
         scol:=Datawell.TableOptions.fieldbyname('Color22').asinteger;
       end;
    else raise Exception.CreateFmt('TFormMain.Special: Invalid sender tag: %d', [stag]);
  end;
  slabel.caption:=str;
  slabel.font.color:=clblack;
  spanel.color:=scol;
  stimer.enabled:=false;
  stimer.interval:=Datawell.TableOptions.fieldbyname('SpecialDuration').asinteger*1000;
  stimer.enabled:=true;
end;

procedure TFormMain.TimerSpecialTimer(Sender: TObject);
var
  stag: integer;
  sfont: TFont;
  spanel: TPanel;
begin
  TTimer(sender).interval:=500;
  stag:=TTimer(sender).tag;
  case stag of
    1: begin
         sfont:=LabelSpecial.font;
         spanel:=PanelSpecial;
       end;
    2: begin
         sfont:=LabelSpecial2.font;
         spanel:=PanelSpecial2;
       end;
    else raise Exception.CreateFmt('TFormMain.TimerSpecialTimer: Invalid sender tag: %d', [stag]);
  end;
  with sfont do begin
    if color = clblack then color:=clgray
    else begin
      color:=clsilver;
      spanel.color:=clgray;
      TTimer(sender).enabled:=false;
    end;
  end;
end;

procedure TFormMain.SetGLine(data: string; which: integer);
var
  gline: TRichEdit;
  work: string;
  i, j, limit: integer;
  colors, begs, legs: TStringList;
begin
  limit:=0;
  data:=copy(data,1,500);
  colors:=TStringList.create;
  begs:=TStringList.create;
  legs:=TStringList.create;
  work:='';
  data:=Datawell.subs('^^','~',data);
  if which = 1 then begin
    gline:=GLine1;
    Datawell.gline1:=data;
  end
  else begin
    gline:=GLine2;
    Datawell.gline2:=data;
  end;
  i:=pos('<',data);
  while i > 0 do begin
    j:=pos('>',data);
    if j > 0 then begin
      colors.add(copy(data,i+1,1));
      work:=copy(data,i+2,j-i-2);
      begs.add(inttostr(i-1));
      legs.add(inttostr(length(work)));
      delete(data,j,1);
      delete(data,i,2);
    end
    else delete(data,i,1);
    i:=pos('<',data);
    inc(limit);
    if limit > 49 then break;
  end;
  gline.hide;
  gline.lines.clear;
  gline.lines.add(' '+data);
  gline.selectall;
  gline.selattributes.color:=clwhite;
  gline.sellength:=0;
  for i:=0 to colors.count-1 do begin
    ColorGLine(gline,strtoint(begs[i])+1,strtoint(legs[i]),FigureGLineColor(colors[i]));
  end;
  gline.show;
  colors.free;
  begs.free;
  legs.free;
end;

procedure TFormMain.ColorGLine(gline: TRichEdit; colorstart, colorlength: integer;
  col: TColor);
begin
  gline.selstart:=colorstart;
  gline.sellength:=colorlength;
  gline.selattributes.color:=col;
  gline.selstart:=0;
  gline.sellength:=0;
end;

function TFormMain.FigureGLineColor(str: string): integer;
begin
  result:=clwhite;
  if str = 'y' then result:=clyellow
  else if str = 'r' then result:=clred
  else if str = 'b' then result:=clblue
  else if str = 'g' then result:=cllime
  else if str = 'c' then result:=claqua
  else if str = 'v' then result:=clfuchsia
  else if str = 's' then result:=clsilver;
end;

procedure TFormMain.FigureEnemyPercent(per: string);
var
  i, oldper: integer;
  high: boolean;
begin
  high:=false;
  oldper:=GaugeEnemy.progress;
  i:=Datawell.ToInt(per);
  if i < 0 then i:=0;
  if screens[4] then begin
    if i = 0 then screenImagery.LabelText.font.color:=clgray
    else screenImagery.LabelText.font.color:=clblack;
  end;
  GaugeEnemy.progress:=i;
  enemys[0]:=false;
  enemys[1]:=false;
  enemys[2]:=false;
  enemys[3]:=false;
  enemys[4]:=false;
  if (i = 100) or (i = 0) then begin
    GaugeEnemy.forecolor:=Datawell.TableOptions.fieldbyname('C1005').asinteger;
    enemys[0]:=true;
    high:=true;
  end
  else if i < Datawell.TableOptions.fieldbyname('Enemy').asinteger then begin
    GaugeEnemy.forecolor:=Datawell.TableOptions.fieldbyname('Cl5').asinteger;
    enemys[1]:=true;
    if oldper >= Datawell.TableOptions.fieldbyname('Enemy').asinteger then DoStatusEvent(15);
  end
  else if i < Datawell.TableOptions.fieldbyname('Enemy2').asinteger then begin
    GaugeEnemy.forecolor:=Datawell.TableOptions.fieldbyname('Cm5').asinteger;
    enemys[2]:=true;
  end
  else if i < 100 then begin
    GaugeEnemy.forecolor:=Datawell.TableOptions.fieldbyname('Ch5').asinteger;
    enemys[3]:=true;
    high:=true;
  end
  else begin
    GaugeEnemy.forecolor:=Datawell.TableOptions.fieldbyname('Co5').asinteger;
    enemys[4]:=true;
    high:=true;
  end;
  if (high) and (oldper < Datawell.TableOptions.fieldbyname('Enemy2').asinteger) then begin
    DoStatusEvent(25);
  end;
  if screens[4] then begin
    screenImagery.GaugeEnemy.maxvalue:=GaugeEnemy.maxvalue;
    screenImagery.GaugeEnemy.progress:=GaugeEnemy.progress;
    screenImagery.GaugeEnemy.forecolor:=GaugeEnemy.forecolor;
  end;
  GaugeEnemy2.maxvalue:=GaugeEnemy.maxvalue;
  GaugeEnemy2.progress:=GaugeEnemy.progress;
  GaugeEnemy2.forecolor:=GaugeEnemy.forecolor;
  if Datawell.TableOptions3.FieldByName('L29').asboolean then begin
    ImageEnemy.visible:=enemys[0];
    ImageEnemyLow.visible:=enemys[1];
    ImageEnemyMedian.visible:=enemys[2];
    ImageEnemyHigh.visible:=enemys[3];
    ImageEnemyBetter.visible:=enemys[4];
    ImageEnemy2.visible:=enemys[0];
    ImageEnemyLow2.visible:=enemys[1];
    ImageEnemyMedian2.visible:=enemys[2];
    ImageEnemyHigh2.visible:=enemys[3];
    ImageEnemyBetter2.visible:=enemys[4];
  end;
end;

procedure TFormMain.UpdateGauge(which: integer; var oldvar: integer; FromOptions: boolean);
var
  GaugeBase: TGauge;
  LabelMax, LabelBase: TLabel;
  i, x, per, oldper: integer;
  high: boolean;
begin
  case which of
    1: begin
         GaugeBase:=GaugeHP;
         LabelMax:=LabelHPMax;
         LabelBase:=LabelHP;
       end;
    2: begin
         GaugeBase:=GaugeSP;
         LabelMax:=LabelSPMax;
         LabelBase:=LabelSP;
       end;
    3: begin
         GaugeBase:=GaugeGP1;
         LabelMax:=LabelGP1Max;
         LabelBase:=LabelGP1;
       end;
    4: begin
         GaugeBase:=GaugeGP2;
         LabelMax:=LabelGP2Max;
         LabelBase:=LabelGP2;
       end;
    else raise Exception.CreateFmt('TFormMain.UpdateGauge: invalid Which value: %d', [which]);
  end;
  high:=false;
  if LabelMax.caption = '' then begin
    x:=Datawell.ToInt(LabelBase.caption);
    if x < 1 then x:=0;
    LabelMax.caption:=inttostr(x);
  end;
  if LabelBase.caption = '' then exit;
  if GaugeBase.maxvalue = 0 then GaugeBase.maxvalue:=1;
  oldper:=trunc(GaugeBase.progress*100/GaugeBase.maxvalue);
  GaugeBase.maxvalue:=Datawell.ToInt(LabelMax.caption);
  if GaugeBase.maxvalue = 0 then GaugeBase.maxvalue:=1;
  i:=Datawell.ToInt(LabelBase.caption);
  per:=trunc(i*100/GaugeBase.maxvalue);
  if i > GaugeBase.maxvalue then GaugeBase.progress:=GaugeBase.maxvalue
  else GaugeBase.progress:=i;
  case which of
    1: begin
         if per < Datawell.TableOptions.fieldbyname('HP').asinteger then begin
           GaugeBase.forecolor:=Datawell.TableOptions.fieldbyname('Cl1').asinteger;
           if (oldper >= Datawell.TableOptions.fieldbyname('HP').asinteger) and
             (not FromOptions) then DoStatusEvent(which+10);
         end
         else if per < Datawell.TableOptions.fieldbyname('HP2').asinteger then begin
           GaugeBase.forecolor:=Datawell.TableOptions.fieldbyname('Cm1').asinteger;
         end
         else if per < 100 then begin
           GaugeBase.forecolor:=Datawell.TableOptions.fieldbyname('Ch1').asinteger;
           high:=true;
         end
         else if per = 100 then begin
           GaugeBase.forecolor:=Datawell.TableOptions.fieldbyname('C1001').asinteger;
           high:=true;
         end
         else begin
           GaugeBase.forecolor:=Datawell.TableOptions.fieldbyname('Co1').asinteger;
           high:=true;
         end;
         if (high) and (oldper < Datawell.TableOptions.fieldbyname('HP2').asinteger) and
           (firststatus) then begin
           DoStatusEvent(which+20);
         end;
       end;
    2: begin
         if per < Datawell.TableOptions.fieldbyname('SP').asinteger then begin
           GaugeBase.forecolor:=Datawell.TableOptions.fieldbyname('Cl2').asinteger;
           if (oldper >= Datawell.TableOptions.fieldbyname('SP').asinteger) and
             (not FromOptions) then DoStatusEvent(which+10);
         end
         else if per < Datawell.TableOptions.fieldbyname('SP2').asinteger then begin
           GaugeBase.forecolor:=Datawell.TableOptions.fieldbyname('Cm2').asinteger;
         end
         else if per < 100 then begin
           GaugeBase.forecolor:=Datawell.TableOptions.fieldbyname('Ch2').asinteger;
           high:=true;
         end
         else if per = 100 then begin
           GaugeBase.forecolor:=Datawell.TableOptions.fieldbyname('C1002').asinteger;
           high:=true;
         end
         else begin
           GaugeBase.forecolor:=Datawell.TableOptions.fieldbyname('Co2').asinteger;
           high:=true;
         end;
         if (high) and (oldper < Datawell.TableOptions.fieldbyname('SP2').asinteger) and
           (firststatus) then begin
           DoStatusEvent(which+20);
         end;
       end;
    3: begin
         if per < Datawell.TableOptions.fieldbyname('GP1').asinteger then begin
           GaugeBase.forecolor:=Datawell.TableOptions.fieldbyname('Cl3').asinteger;
           if (oldper >= Datawell.TableOptions.fieldbyname('GP1').asinteger) and
             (not FromOptions) then DoStatusEvent(which+10);
         end
         else if per < Datawell.TableOptions.fieldbyname('GP12').asinteger then begin
           GaugeBase.forecolor:=Datawell.TableOptions.fieldbyname('Cm3').asinteger;
         end
         else if per < 100 then begin
           GaugeBase.forecolor:=Datawell.TableOptions.fieldbyname('Ch3').asinteger;
           high:=true;
         end
         else if per = 100 then begin
           GaugeBase.forecolor:=Datawell.TableOptions.fieldbyname('C1003').asinteger;
           high:=true;
         end
         else begin
           GaugeBase.forecolor:=Datawell.TableOptions.fieldbyname('Co3').asinteger;
           high:=true;
         end;
         if (high) and (oldper < Datawell.TableOptions.fieldbyname('GP12').asinteger) and
           (firststatus) then begin
           DoStatusEvent(which+20);
         end;
       end;
    4: begin
         if per < Datawell.TableOptions.fieldbyname('GP2').asinteger then begin
           GaugeBase.forecolor:=Datawell.TableOptions.fieldbyname('Cl4').asinteger;
           if (oldper >= Datawell.TableOptions.fieldbyname('GP2').asinteger) and
             (not FromOptions) then DoStatusEvent(which+10);
         end
         else if per < Datawell.TableOptions.fieldbyname('GP22').asinteger then begin
           GaugeBase.forecolor:=Datawell.TableOptions.fieldbyname('Cm4').asinteger;
         end
         else if per < 100 then begin
           GaugeBase.forecolor:=Datawell.TableOptions.fieldbyname('Ch4').asinteger;
           high:=true;
         end
         else if per = 100 then begin
           GaugeBase.forecolor:=Datawell.TableOptions.fieldbyname('C1004').asinteger;
           high:=true;
         end
         else begin
           GaugeBase.forecolor:=Datawell.TableOptions.fieldbyname('Co4').asinteger;
           high:=true;
         end;
         if (high) and (oldper < Datawell.TableOptions.fieldbyname('GP22').asinteger) and
           (firststatus) then begin
           DoStatusEvent(which+20);
         end;
       end;
  end;
  if Datawell.TableOptions3.fieldbyname('L43').asboolean then begin
    LabelBase.font.color:=GaugeBase.forecolor;
    LabelMax.font.color:=GaugeBase.forecolor;
  end;
end;

procedure TFormMain.GrabMedia(filename, URL: string);
var
  failed, issound, ismusic, isimage, isavi: boolean;
  work, tempfile: string;
begin
  issound:=false;
  ismusic:=false;
  isimage:=false;
  isavi:=false;
  work:=lowercase(copy(filename,length(filename)-2,3));
  if work = 'wav' then issound:=true
  else if (work = 'mid') or (work = 'rmi') or (work = 'mp3') then ismusic:=true
  else if (work = 'bmp') or (work = 'gif') then isimage:=true
  else if work = 'avi' then isavi:=true;
  if (not issound) and (not ismusic) and (not isimage) and (not isavi) then exit;
  if (issound) or (ismusic) then tempfile:=Datawell.getsounddir+'\'+filename
  else tempfile:=Datawell.getimagedir+'\'+filename;
  tempfile:=Datawell.subs('/','\',tempfile);
  failed:=false;
  HTTP.URL:=url;
  HTTP.RcvdStream:=TFileStream.Create(tempfile,fmCreate);
  try try HTTP.get; except on E: EHttpException do failed:=true; else raise; end;
  finally HTTP.RcvdStream.free; HTTP.RcvdStream:=nil; end;
  if failed then begin
    if fileexists(tempfile) then deletefile(tempfile);
    exit;
  end;
  if not fileexists(tempfile) then exit;
  if Datawell.TableOptions3.fieldbyname('L35').asboolean then begin
    systemtext(#10+'File: "'+filename+'" auto-downloaded from:',0);
    systemtext('      '+url,0);
  end;
  if not Datawell.TableOptions3.fieldbyname('L34').asboolean then exit;
  if issound then PlaySound(tempfile,1,1,0,false)
  else if ismusic then begin
    repeatmusic:=0;
    PlayMusic(tempfile,false);
  end
  else if isimage then ShowImage(tempfile,'')
  else if isavi then ShowAVI(tempfile,'',0,0,false);
end;

procedure TFormMain.DownloadMedia(filename, URL: string);
var
  issound, isimage: boolean;
  work: string;
begin
  if filename = '' then exit;
  if url = '' then exit;
  if not Datawell.TableOptions3.fieldbyname('L30').asboolean then exit;
  issound:=false;
  isimage:=false;
  work:=lowercase(copy(filename,length(filename)-2,3));
  if (work = 'wav') or (work = 'mid') or (work = 'rmi') then issound:=true;
  if (work = 'bmp') or (work = 'gif') or (work = 'avi') then isimage:=true;
  if (not issound) and (not isimage) then exit;
  if (issound) and (not directoryexists(Datawell.getsounddir)) then exit;
  if (isimage) and (not directoryexists(Datawell.getimagedir)) then exit;
  filename:=Datawell.subs(' ','_',filename);
  if (issound) and (fileexists(Datawell.getsounddir+'\'+filename)) then exit;
  if (isimage) and (fileexists(Datawell.getimagedir+'\'+filename)) then exit;
  DLMedia.add(filename+'|||'+url);
  if grabbingmedia then exit;
  grabbingmedia:=true;
  TimerAutoDownload.enabled:=false;
  TimerAutoDownload.enabled:=true;
end;

procedure TFormMain.TimerAutoDownloadTimer(Sender: TObject);
var
  work, file1, url1: string;
  i: integer;
begin
  TimerAutoDownload.enabled:=false;
  while DLMedia.Count > 0 do begin
    work:=DLMedia[0];
    DLMedia.delete(0);
    i:=pos('|||',work);
    file1:=copy(work,1,i-1);
    url1:=copy(work,i+3,9999);
    GrabMedia(file1,url1);
  end;
  grabbingmedia:=false;
end;

procedure TFormMain.MenuCloseAllScreensClick(Sender: TObject);
begin
  if screens[0] then screenChat.close;
  if screens[1] then screenTell.close;
  if screens[2] then screenRoom.close;
  if screens[4] then screenImagery.close;
  if screens[6] then screenFiltered.close;
  if screens[10] then screenCanvas.close;
  if screens[11] then screenEditor.close;
end;

procedure TFormMain.LoadScreen(which: integer);
begin
  if screens[which] then exit;
  screens[which]:=true;
  if which = 0 then begin
    screenChat:=TFormChat.create(self);
    screenChat.MenuPanic.shortcut:=MenuPanic.shortcut;
    screenChat.top:=Datawell.TableOptions.fieldbyname('ChatTop').asinteger;
    screenChat.left:=Datawell.TableOptions.fieldbyname('ChatLeft').asinteger;
    screenChat.height:=Datawell.TableOptions.fieldbyname('ChatHeight').asinteger;
    screenChat.width:=Datawell.TableOptions.fieldbyname('ChatWidth').asinteger;
    if Datawell.TableOptions.fieldbyname('ChatStayOnTop').asboolean then screenChat.formstyle:=fsstayontop
    else screenChat.formstyle:=fsnormal;
    screenChat.MenuStayOnTop.checked:=Datawell.TableOptions.fieldbyname('ChatStayOnTop').asboolean;
    if Datawell.TableOptions.fieldbyname('ChatExpanded').asboolean then begin
      if not screenChat.MenuExpanded.checked then screenChat.MenuExpanded.click;
    end
    else if screenChat.MenuExpanded.checked then screenChat.MenuExpanded.click;
    case  Datawell.TableOptions.fieldbyname('ChatLineHeight').asinteger of
      2: screenChat.Menu2.click;
      3: screenChat.Menu3.click;
      else screenChat.Menu1.click;
    end;
    if (Datawell.player <> Datawell.lastplayer) or (Datawell.mud <> Datawell.lastmud) then
      screenChat.MenuClearAll.click;
    screenChat.LineGridHeight:=Datawell.TableOptions.fieldbyname('ChatLineGridHeight').asinteger;
    screenChat.MenuShowLineGrid.checked:=Datawell.TableOptions.fieldbyname('ChatShowLineGrid').asboolean;
    screenChat.UpdateLinebase;
    screenChat.show;
    if not Datawell.TableOptions3.fieldbyname('L1').asboolean then begin
      if messagedlg('The Chat Monitor is currently disabled.  Enable it now?',
        mtconfirmation,[mbyes,mbno],0) = mryes then begin
        Datawell.TableOptions3.edit;
        Datawell.TableOptions3.fieldbyname('L1').asboolean:=true;
        Datawell.TableOptions3.post;
      end;
    end;
    MenuShowChat.checked:=true;
  end
  else if which = 1 then begin
    screenTell:=TFormTellhist.create(self);
    screenTell.MenuPanic.shortcut:=MenuPanic.shortcut;
    screenTell.top:=Datawell.TableOptions.fieldbyname('TellTop').asinteger;
    screenTell.left:=Datawell.TableOptions.fieldbyname('TellLeft').asinteger;
    screenTell.height:=Datawell.TableOptions.fieldbyname('TellHeight').asinteger;
    screenTell.width:=Datawell.TableOptions.fieldbyname('TellWidth').asinteger;
    if Datawell.TableOptions.fieldbyname('TellStayOnTop').asboolean then screenTell.formstyle:=fsstayontop
    else screenTell.formstyle:=fsnormal;
    screenTell.MenuStayOnTop.checked:=Datawell.TableOptions.fieldbyname('TellStayOnTop').asboolean;
    if Datawell.TableOptions.fieldbyname('TellExpanded').asboolean then begin
      if not screenTell.MenuExpanded.checked then screenTell.MenuExpanded.click;
    end
    else begin
      if screenTell.MenuExpanded.checked then screenTell.MenuExpanded.click;
    end;
    if (Datawell.player <> Datawell.lastplayer) or (Datawell.mud <> Datawell.lastmud) then
      screenTell.MenuClearAll.click;
    screenTell.show;
    if not Datawell.TableOptions3.fieldbyname('L17').asboolean then begin
      if messagedlg('The Tell Monitor is currently disabled.  Enable it now?',
        mtconfirmation,[mbyes,mbno],0) = mryes then begin
        Datawell.TableOptions3.edit;
        Datawell.TableOptions3.fieldbyname('L17').asboolean:=true;
        Datawell.TableOptions3.post;
      end;
    end;
    MenuShowTell.checked:=true;
  end
  else if which = 2 then begin
    screenRoom:=TFormRoomMonitor.create(self);
    screenRoom.MenuPanic.shortcut:=MenuPanic.shortcut;
    screenRoom.top:=Datawell.TableOptions3.fieldbyname('I31').asinteger;
    screenRoom.left:=Datawell.TableOptions3.fieldbyname('I30').asinteger;
    if Datawell.TableOptions3.fieldbyname('L56').asboolean then screenRoom.formstyle:=fsstayontop
    else screenRoom.formstyle:=fsnormal;
    screenRoom.MenuStayOnTop.checked:=Datawell.TableOptions3.fieldbyname('L56').asboolean;
    screenRoom.show;
    MenuShowRoom.checked:=true;
  end
  else if which = 4 then begin
    screenImagery:=TFormImagery.create(self);
    screenImagery.MenuPanic.shortcut:=MenuPanic.shortcut;
    screenImagery.LabelText.caption:=ImageEnemyName.hint;
    screenImagery.GaugeEnemy.maxvalue:=GaugeEnemy.maxvalue;
    screenImagery.GaugeEnemy.progress:=GaugeEnemy.progress;
    screenImagery.GaugeEnemy.forecolor:=GaugeEnemy.forecolor;
    screenImagery.GaugeEnemy.backcolor:=GaugeHP.backcolor;
    screenImagery.top:=Datawell.TableOptions.fieldbyname('ImageryTop').asinteger;
    screenImagery.left:=Datawell.TableOptions.fieldbyname('ImageryLeft').asinteger;
    screenImagery.height:=Datawell.TableOptions.fieldbyname('ImageryHeight').asinteger;
    screenImagery.width:=Datawell.TableOptions.fieldbyname('ImageryWidth').asinteger;
    screenImagery.PanelImage.color:=Datawell.TableOptions.fieldbyname('ImageryColor').asinteger;
    screenImagery.PanelAVI.color:=Datawell.TableOptions.fieldbyname('ImageryColor').asinteger;
    if Datawell.TableOptions.fieldbyname('ImageryStayOnTop').asboolean then screenImagery.formstyle:=fsstayontop
    else screenImagery.formstyle:=fsnormal;
    screenImagery.MenuStayOnTop.checked:=Datawell.TableOptions.fieldbyname('ImageryStayOnTop').asboolean;
    screenImagery.MenuShowGauge.checked:=Datawell.TableOptions.fieldbyname('ImageryShowGauge').asboolean;
    screenImagery.MenuShowImageLabel.checked:=Datawell.TableOptions.fieldbyname('ImageryShowLabel').asboolean;
    screenImagery.MenuAutoRepeat.checked:=Datawell.TableOptions3.fieldbyname('L33').asboolean;
    screenImagery.UpdatePanels;
    screenImagery.show;
    MenuShowImagery.checked:=true;
  end
  else if which = 6 then begin
    screenFiltered:=TFormFiltered.create(self);
    screenFiltered.MenuPanic.shortcut:=MenuPanic.shortcut;
    screenFiltered.top:=Datawell.TableOptions.fieldbyname('FilteredTop').asinteger;
    screenFiltered.left:=Datawell.TableOptions.fieldbyname('FilteredLeft').asinteger;
    screenFiltered.height:=Datawell.TableOptions.fieldbyname('FilteredHeight').asinteger;
    screenFiltered.width:=Datawell.TableOptions.fieldbyname('FilteredWidth').asinteger;
    if Datawell.TableOptions.fieldbyname('FilteredStayOnTop').asboolean then screenFiltered.formstyle:=fsstayontop
    else screenFiltered.formstyle:=fsnormal;
    screenFiltered.MenuStayOnTop.checked:=Datawell.TableOptions.fieldbyname('FilteredStayOnTop').asboolean;
    screenFiltered.show;
    MenuShowFiltered.checked:=true;
  end
  else if which = 10 then begin
    screenCanvas:=TFormCanvas.create(self);
    screenCanvas.MenuPanic.shortcut:=MenuPanic.shortcut;
    screenCanvas.top:=Datawell.TableOptions3.fieldbyname('I12').asinteger;
    screenCanvas.left:=Datawell.TableOptions3.fieldbyname('I13').asinteger;
    screenCanvas.height:=Datawell.TableOptions3.fieldbyname('I14').asinteger;
    screenCanvas.width:=Datawell.TableOptions3.fieldbyname('I15').asinteger;
    screenCanvas.PanelMain.color:=Datawell.TableOptions3.fieldbyname('I16').asinteger;
    if Datawell.TableOptions3.fieldbyname('L19').asboolean then screenCanvas.formstyle:=fsstayontop
    else screenCanvas.formstyle:=fsnormal;
    screenCanvas.MenuStayOnTop.checked:=Datawell.TableOptions3.fieldbyname('L19').asboolean;
    screenCanvas.PopupSnap.checked:=Datawell.TableOptions3.fieldbyname('L21').asboolean;
    screenCanvas.MenuHideTitlebar.checked:=Datawell.TableOptions3.fieldbyname('L22').asboolean;
    if screenCanvas.MenuHideTitlebar.checked then screenCanvas.borderstyle:=bsnone;
    screenCanvas.Grid.width:=1000;
    screenCanvas.Grid.height:=1000;
    screenCanvas.DrawGrid;
    screenCanvas.Grid.align:=alclient;
    screenCanvas.LoadOptions;
    Datawell.TableVariables.first;
    while not Datawell.TableVariables.EOF do begin
      UpdateCanvasVariable('@'+Datawell.TableVariables.fieldbyname('FVariable').asstring,Datawell.TableVariables.fieldbyname('FValue').asstring);
      Datawell.TableVariables.next;
    end;
    UpdateCanvasVariable('@HP',LabelHP.caption);
    UpdateCanvasVariable('@MAXHP',LabelHPMAX.caption);
    UpdateCanvasVariable('@SP',LabelSP.caption);
    UpdateCanvasVariable('@MAXSP',LabelSPMAX.caption);
    UpdateCanvasVariable('@GP1',LabelGP1.caption);
    UpdateCanvasVariable('@MAXGP1',LabelGP1MAX.caption);
    UpdateCanvasVariable('@GP2',LabelGP2.caption);
    UpdateCanvasVariable('@MAXGP2',LabelGP2MAX.caption);
    UpdateCanvasVariable('@ENEMY',inttostr(GaugeEnemy.progress));
    UpdateCanvasVariable('@ENAME',GetEName);
    UpdateCanvasVariable('@GLINE1',Datawell.gline1);
    UpdateCanvasVariable('@GLINE2',Datawell.gline2);
    UpdateCanvasVariable('@CAPTION',caption);
    UpdateCanvasVariable('@AA',scripts.GetVarValueAsString('AA'));
    UpdateCanvasVariable('@BB',scripts.GetVarValueAsString('BB'));
    UpdateCanvasVariable('@CC',scripts.GetVarValueAsString('CC'));
    UpdateCanvasVariable('@DD',scripts.GetVarValueAsString('DD'));
    UpdateCanvasVariable('@EE',scripts.GetVarValueAsString('EE'));
    UpdateCanvasVariable('@FF',scripts.GetVarValueAsString('FF'));
    screenCanvas.show;
    screenCanvas.DrawGrid;
    screenCanvas.grid.hide;
    MenuShowCanvas.checked:=true;
  end
  else if which = 11 then begin
    screenEditor:=TFormEditor.create(self);
    LoadEditorOptions;
  end;
  UpdateWindowCaptions;
end;

procedure TFormMain.UnloadScreen(which: integer);
begin
  if which = 0 then begin
    if screens[which] then begin
      with screenChat do begin
        Datawell.TableOptions.edit;
        Datawell.TableOptions.fieldbyname('ChatTop').asinteger:=top;
        Datawell.TableOptions.fieldbyname('ChatLeft').asinteger:=left;
        Datawell.TableOptions.fieldbyname('ChatHeight').asinteger:=height;
        Datawell.TableOptions.fieldbyname('ChatWidth').asinteger:=width;
        Datawell.TableOptions.fieldbyname('ChatStayOnTop').asboolean:=MenuStayOnTop.checked;
        Datawell.TableOptions.fieldbyname('ChatExpanded').asboolean:=MenuExpanded.checked;
        if Menu2.checked then Datawell.TableOptions.fieldbyname('ChatLineHeight').asinteger:=2
        else if Menu3.checked then Datawell.TableOptions.fieldbyname('ChatLineHeight').asinteger:=3
        else Datawell.TableOptions.fieldbyname('ChatLineHeight').asinteger:=1;
        Datawell.TableOptions.fieldbyname('ChatLineGridHeight').asinteger:=LineGridHeight;
        Datawell.TableOptions.fieldbyname('ChatShowLineGrid').asboolean:=MenuShowLineGrid.checked;
        Datawell.TableOptions.post;
      end;
      screens[which]:=false;
      screenChat.free;
    end;
    MenuShowChat.checked:=false;
  end
  else if which = 1 then begin
    if screens[which] then begin
      with screenTell do begin
        Datawell.TableOptions.edit;
        Datawell.TableOptions.fieldbyname('TellTop').asinteger:=top;
        Datawell.TableOptions.fieldbyname('TellLeft').asinteger:=left;
        Datawell.TableOptions.fieldbyname('TellHeight').asinteger:=height;
        Datawell.TableOptions.fieldbyname('TellWidth').asinteger:=width;
        Datawell.TableOptions.fieldbyname('TellStayOnTop').asboolean:=MenuStayOnTop.checked;
        Datawell.TableOptions.fieldbyname('TellExpanded').asboolean:=MenuExpanded.checked;
        Datawell.TableOptions.post;
      end;
      screens[which]:=false;
      screenTell.free;
    end;
    MenuShowTell.checked:=false;
  end
  else if which = 2 then begin
    if screens[which] then begin
      with screenRoom do begin
        Datawell.TableOptions3.edit;
        Datawell.TableOptions3.fieldbyname('I31').asinteger:=top;
        Datawell.TableOptions3.fieldbyname('I30').asinteger:=left;
        Datawell.TableOptions3.fieldbyname('L56').asboolean:=MenuStayOnTop.checked;
        Datawell.TableOptions3.post;
      end;
      screens[which]:=false;
      screenRoom.free;
    end;
    MenuShowRoom.checked:=false;
  end
  else if which = 4 then begin
    if screens[which] then begin
      with screenImagery do begin
        Datawell.TableOptions.edit;
        Datawell.TableOptions.fieldbyname('ImageryTop').asinteger:=top;
        Datawell.TableOptions.fieldbyname('ImageryLeft').asinteger:=left;
        Datawell.TableOptions.fieldbyname('ImageryHeight').asinteger:=height;
        Datawell.TableOptions.fieldbyname('ImageryWidth').asinteger:=width;
        Datawell.TableOptions.fieldbyname('ImageryColor').asinteger:=PanelImage.color;
        Datawell.TableOptions.fieldbyname('ImageryStayOnTop').asboolean:=MenuStayOnTop.checked;
        Datawell.TableOptions.fieldbyname('ImageryShowGauge').asboolean:=MenuShowGauge.checked;
        Datawell.TableOptions.fieldbyname('ImageryShowLabel').asboolean:=MenuShowImageLabel.checked;
        Datawell.TableOptions.post;
        Datawell.TableOptions3.edit;
        Datawell.TableOptions3.fieldbyname('L33').asboolean:=MenuAutoRepeat.checked;
        Datawell.TableOptions3.post;
      end;
      screens[which]:=false;
      screenImagery.free;
    end;
    MenuShowImagery.checked:=false;
  end
  else if which = 6 then begin
    if screens[which] then begin
      with screenFiltered do begin
        Datawell.TableOptions.edit;
        Datawell.TableOptions.fieldbyname('FilteredTop').asinteger:=top;
        Datawell.TableOptions.fieldbyname('FilteredLeft').asinteger:=left;
        Datawell.TableOptions.fieldbyname('FilteredHeight').asinteger:=height;
        Datawell.TableOptions.fieldbyname('FilteredWidth').asinteger:=width;
        Datawell.TableOptions.fieldbyname('FilteredStayOnTop').asboolean:=MenuStayOnTop.checked;
        Datawell.TableOptions.post;
      end;
      screens[which]:=false;
      screenFiltered.free;
    end;
    MenuShowFiltered.checked:=false;
  end
  else if which = 10 then begin
    if screens[which] then begin
      with screenCanvas do begin
        SaveOptions;
        Datawell.TableOptions3.edit;
        Datawell.TableOptions3.fieldbyname('I12').asinteger:=top;
        Datawell.TableOptions3.fieldbyname('I13').asinteger:=left;
        Datawell.TableOptions3.fieldbyname('I14').asinteger:=height-PanelTools.height;
        Datawell.TableOptions3.fieldbyname('I15').asinteger:=width;
        Datawell.TableOptions3.fieldbyname('I16').asinteger:=PanelMain.color;
        Datawell.TableOptions3.fieldbyname('L19').asboolean:=MenuStayOnTop.checked;
        Datawell.TableOptions3.fieldbyname('L21').asboolean:=PopupSnap.checked;
        Datawell.TableOptions3.fieldbyname('L22').asboolean:=MenuHideTitlebar.checked;
        Datawell.TableOptions3.post;
      end;
      screens[which]:=false;
      screenCanvas.free;
    end;
    MenuShowCanvas.checked:=false;
  end
  else if which = 11 then begin
    if screens[which] then begin
      if not loginclose then begin
        with screenEditor do begin
          Datawell.TableOptions.edit;
          Datawell.TableOptions.fieldbyname('EditorTop').asinteger:=top;
          Datawell.TableOptions.fieldbyname('EditorLeft').asinteger:=left;
          Datawell.TableOptions.fieldbyname('EditorHeight').asinteger:=height;
          Datawell.TableOptions.fieldbyname('EditorWidth').asinteger:=width;
          Datawell.TableOptions.fieldbyname('EditorFontName').asstring:=Editor1.font.name;
          if Editor1.font.style = [fsbold] then Datawell.TableOptions.fieldbyname('EditorFontStyle').asinteger:=1
          else if Editor1.font.style = [fsitalic] then Datawell.TableOptions.fieldbyname('EditorFontStyle').asinteger:=2
          else if Editor1.font.style = [fsbold, fsitalic] then Datawell.TableOptions.fieldbyname('EditorFontStyle').asinteger:=3
          else Datawell.TableOptions.fieldbyname('EditorFontStyle').asinteger:=0;
          Datawell.TableOptions.fieldbyname('EditorFontSize').asinteger:=Editor1.font.size;
          Datawell.TableOptions.fieldbyname('EditorFColor').asinteger:=Editor1.font.color;
          Datawell.TableOptions.fieldbyname('EditorBColor').asinteger:=Editor1.color;
          Datawell.TableOptions.fieldbyname('EditorWrap').asboolean:=MenuEnableWordWrap.checked;
          Datawell.TableOptions.fieldbyname('AutotypeSave').asboolean:=MenuSaveAlert.checked;
          Datawell.TableOptions.fieldbyname('EditorClear').asboolean:=MenuClearOnAutotype.checked;
          Datawell.TableOptions.fieldbyname('EditorAsk').asboolean:=MenuAskOnEmpty.checked;
          Datawell.TableOptions.fieldbyname('EditorShowWidthbar').asboolean:=MenuShowWidthBar.checked;
          Datawell.TableOptions.fieldbyname('EditorStayOnTop').asboolean:=MenuStayOnTop.checked;
          Datawell.TableOptions.post;
        end;
      end;
      screens[which]:=false;
    end;
  end
  else if which = 12 then begin
    screens[which]:=false;
    MenuShowCartographer.checked:=false;
  end;
end;

procedure TFormMain.PopupGLine1Click(Sender: TObject);
var str: string;
begin
  case TComponent(sender).tag of
    1: str:=GLine1.text;
    2: str:=GLine2.text;
  end;
  delete(str,1,1);
  delete(str,length(str)-1,2);
  MemoCopy.text:=str;
  MemoCopy.selectall;
  MemoCopy.CopyToClipboard;
end;

procedure TFormMain.TimerChartTimer(Sender: TObject);
begin
  TimerChart.enabled:=false;
  FormMap.FinalizeLink(true);
end;

procedure TFormMain.ImageDisableEventClick(Sender: TObject);
begin
  EnableEvents(TComponent(sender).tag);
end;

procedure TFormMain.EnableEvents(b: integer);
begin
  case b of
    0: begin
         ImageDisableEvent.hide;
         ImageEnableEvent.show;
         systemtext('All events & ticker actions disabled',0);
       end;
    1: begin
         ImageEnableEvent.hide;
         ImageDisableEvent.show;
         systemtext('Events & ticker actions re-enabled',0);
       end;
  end;
  SetupEvents;
end;

procedure TFormMain.AppendToAutotyper(data: string);
var which: integer;
begin
  which:=0;
  if copy(data,2,1) = '|' then begin
    which:=Datawell.toint(copy(data,1,1));
    delete(data,1,2);
  end;
  if which > 4 then which:=0;
  if which > 1 then begin
    if not Datawell.CheckRinged(false,'multiple Autotyper files') then exit;
  end;
  if not screens[11] then begin
    LoadScreen(11);
    screenEditor.windowstate:=wsnormal;
    show;
  end;
  if which > 0 then begin
    case which of
      1: screenEditor.Tabs.activepage:=screenEditor.Tab1;
      2: screenEditor.Tabs.activepage:=screenEditor.Tab2;
      3: screenEditor.Tabs.activepage:=screenEditor.Tab3;
      4: screenEditor.Tabs.activepage:=screenEditor.Tab4;
    end;
  end;
  screenEditor.ActiveEditor.lines.add(data);
end;

procedure TFormMain.LoadSkin(index: integer);
var
  b1, b2: TBitMap;
  h, w, x, y: integer;
  filename: string;
  im: TImage;
begin
  if (index = 3) then exit;
  if (index < 1) or (index > 3) then exit;
  case index of
    1: filename:=Datawell.TableOptions3.fieldbyname('S66').asstring;
    2: filename:=Datawell.TableOptions3.fieldbyname('S67').asstring;
    3: filename:=Datawell.TableOptions3.fieldbyname('S68').asstring;
  end;
  if not FileExists(filename) then begin
    case index of
      1: filename:=Datawell.exedir+'\hp1.bmp';
      2: filename:=Datawell.exedir+'\hp2.bmp';
      3: filename:=Datawell.exedir+'\status.bmp';
    end;
  end;
  case index of
    1: im:=ImageHP1Bar;
    2: im:=ImageHP2Bar;
    else raise Exception.CreateFmt('TFormMain.LoadSkin: invalid index value: %d', [index]);
  end;
  if not FileExists(filename) then begin
    im.hide;
    exit;
  end;
  b2:=TBitMap.create;
  b1:=TBitMap.create;
  try
    b1.loadfromfile(filename);
    b2.assign(b1);
    b2.dormant;
    b2.freeimage;
    h:=b2.height;
    w:=b2.width;
    if (w > 0) and (h > 0) then begin
      x:=0;
      while x < im.width do begin
        y:=0;
        while y < im.height do begin
          with im.canvas do begin
            brush.color:=clyellow;
            BrushCopy(bounds(x,y,w,h),b2,bounds(0,0,w,h),clyellow);
          end;
          inc(y,h);
        end;
        inc(x,w);
      end;
    end;
    b2.releasehandle;
  finally
    b1.free;
    b2.free;
  end;
  im.show;
end;

procedure TFormMain.UpdateHPBars;
var hpl, spl, gp1l, gp2l, el: integer;
begin
  LabelSlash1.font.color:=Datawell.TableOptions3.fieldbyname('I21').asinteger;
  if Datawell.TableOptions3.fieldbyname('L43').asboolean then begin
    LabelHP.font.color:=GaugeHP.forecolor;
    LabelHPMax.font.color:=GaugeHP.forecolor;
    LabelSP.font.color:=GaugeSP.forecolor;
    LabelSPMax.font.color:=GaugeSP.forecolor;
    LabelGP1.font.color:=GaugeGP1.forecolor;
    LabelGP1Max.font.color:=GaugeGP1.forecolor;
    LabelGP2.font.color:=GaugeGP2.forecolor;
    LabelGP2Max.font.color:=GaugeGP2.forecolor;
    LabelEName.font.color:=GaugeHP.forecolor;
    LabelEName2.font.color:=GaugeHP.forecolor;
  end
  else begin
    LabelHP.font.color:=LabelSlash1.font.color;
    LabelHPMax.font.color:=LabelSlash1.font.color;
    LabelSP.font.color:=LabelSlash1.font.color;
    LabelSPMax.font.color:=LabelSlash1.font.color;
    LabelGP1.font.color:=LabelSlash1.font.color;
    LabelGP1Max.font.color:=LabelSlash1.font.color;
    LabelGP2.font.color:=LabelSlash1.font.color;
    LabelGP2Max.font.color:=LabelSlash1.font.color;
    LabelEName.font.color:=LabelSlash1.font.color;
    LabelEName2.font.color:=LabelSlash1.font.color;
  end;
  LabelSlash2.font.color:=LabelSlash1.font.color;
  LabelSlash3.font.color:=LabelSlash1.font.color;
  LabelSlash4.font.color:=LabelSlash1.font.color;
  PanelHP1Bar.color:=Datawell.TableOptions3.fieldbyname('I20').asinteger;
  PanelHP2Bar.color:=Datawell.TableOptions3.fieldbyname('I22').asinteger;
  GaugeHP.backcolor:=Datawell.TableOptions3.fieldbyname('I19').asinteger;
  GaugeSP.backcolor:=GaugeHP.backcolor;
  GaugeGP1.backcolor:=GaugeHP.backcolor;
  GaugeGP2.backcolor:=GaugeHP.backcolor;
  GaugeEnemy.backcolor:=GaugeHP.backcolor;
  GaugeEnemy2.backcolor:=GaugeHP.backcolor;
  GaugeHP.showtext:=Datawell.TableOptions3.fieldbyname('L42').asboolean;
  GaugeHP.showtext:=GaugeHP.showtext;
  GaugeSP.showtext:=GaugeHP.showtext;
  GaugeGP1.showtext:=GaugeHP.showtext;
  GaugeGP2.showtext:=GaugeHP.showtext;
  GaugeEnemy.showtext:=GaugeHP.showtext;
  if screens[4] then begin
    screenImagery.GaugeEnemy.maxvalue:=GaugeEnemy.maxvalue;
    screenImagery.GaugeEnemy.progress:=GaugeEnemy.progress;
    screenImagery.GaugeEnemy.forecolor:=GaugeEnemy.forecolor;
    screenImagery.GaugeEnemy.backcolor:=GaugeHP.backcolor;
  end;
// Show Elements
  hpl:=5;
  spl:=5;
  gp1l:=5;
  gp2l:=5;
  el:=5;
  if Datawell.TableOptions3.FieldByName('L25').asboolean then begin
    inc(spl,112);
    inc(gp1l,112);
    inc(gp2l,112);
    inc(el,112);
  end;
  if Datawell.TableOptions3.FieldByName('L26').asboolean then begin
    inc(gp1l,112);
    inc(gp2l,112);
    inc(el,112);
  end;
  if Datawell.TableOptions3.FieldByName('L27').asboolean then begin
    inc(gp2l,112);
    inc(el,112);
  end;
  if Datawell.TableOptions3.FieldByName('L28').asboolean then begin
    inc(el,112);
  end;
  if Datawell.TableOptions3.FieldByName('L25').asboolean then begin
    ImageHP2.left:=hpl;
    ImageHP.left:=hpl;
    GaugeHP.left:=hpl+9;
    ihp1.left:=hpl+11;
    ihp2.left:=hpl+11;
    ihp3.left:=hpl+11;
    ShapeHP.left:=hpl+91;
    LabelHP.left:=hpl+16;
    LabelSlash1.left:=hpl+55;
    LabelHPMax.left:=hpl+63;
  end;
  if Datawell.TableOptions3.FieldByName('L26').asboolean then begin
    ImageSP2.left:=spl;
    ImageSP.left:=spl;
    GaugeSP.left:=spl+9;
    isp1.left:=spl+11;
    isp2.left:=spl+11;
    isp3.left:=spl+11;
    ShapeSP.left:=spl+91;
    LabelSP.left:=spl+16;
    LabelSlash2.left:=spl+55;
    LabelSPMax.left:=spl+63;
  end;
  if Datawell.TableOptions3.FieldByName('L27').asboolean then begin
    ImageGP12.left:=gp1l;
    ImageGP1.left:=gp1l;
    GaugeGP1.left:=gp1l+9;
    igp11.left:=gp1l+11;
    igp12.left:=gp1l+11;
    igp13.left:=gp1l+11;
    ShapeGP1.left:=gp1l+91;
    LabelGP1.left:=gp1l+16;
    LabelSlash3.left:=gp1l+55;
    LabelGP1Max.left:=gp1l+63;
  end;
  if Datawell.TableOptions3.FieldByName('L28').asboolean then begin
    ImageGP22.left:=gp2l;
    ImageGP2.left:=gp2l;
    GaugeGP2.left:=gp2l+9;
    igp21.left:=gp2l+11;
    igp22.left:=gp2l+11;
    igp23.left:=gp2l+11;
    ShapeGP2.left:=gp2l+91;
    LabelGP2.left:=gp2l+16;
    LabelSlash4.left:=gp2l+55;
    LabelGP2Max.left:=gp2l+63;
  end;
  if Datawell.TableOptions3.FieldByName('L29').asboolean then begin
    ImageEnemy.left:=el;
    ImageEnemyLow.left:=el;
    ImageEnemyMedian.left:=el;
    ImageEnemyHigh.left:=el;
    ImageEnemyBetter.left:=el;
    ImageEnemy2.left:=el;
    ImageEnemyLow2.left:=el;
    ImageEnemyMedian2.left:=el;
    ImageEnemyHigh2.left:=el;
    ImageEnemyBetter2.left:=el;
    GaugeEnemy.left:=el+9;
    GaugeEnemy2.left:=el+9;
    ShapeEnemy.left:=el+91;
    ShapeEnemy2.left:=el+91;
    ImageEnemyName2.left:=el+11;
    ImageEnemyName.left:=el+11;
    LabelEName.left:=el+112;
    LabelEName2.left:=el+112;
  end;
  ImageHP2.visible:=Datawell.TableOptions3.FieldByName('L25').asboolean;
  ImageHP.visible:=ImageHP2.visible;
  LabelHP.visible:=ImageHP2.visible;
  LabelHPMax.visible:=ImageHP2.visible;
  LabelSlash1.visible:=ImageHP2.visible;
  GaugeHP.visible:=ImageHP2.visible;
  ShapeHP.visible:=ImageHP2.visible;
  ihp1.visible:=ImageHP2.visible;
  ihp2.visible:=ImageHP2.visible;
  ihp3.visible:=ImageHP2.visible;
  ImageSP2.visible:=Datawell.TableOptions3.FieldByName('L26').asboolean;
  ImageSP.visible:=ImageSP2.visible;
  LabelSP.visible:=ImageSP2.visible;
  LabelSPMax.visible:=ImageSP2.visible;
  LabelSlash2.visible:=ImageSP2.visible;
  GaugeSP.visible:=ImageSP2.visible;
  ShapeSP.visible:=ImageSP2.visible;
  isp1.visible:=ImageSP2.visible;
  isp2.visible:=ImageSP2.visible;
  isp3.visible:=ImageSP2.visible;
  ImageGP12.visible:=Datawell.TableOptions3.FieldByName('L27').asboolean;
  ImageGP1.visible:=ImageGP12.visible;
  LabelGP1.visible:=ImageGP12.visible;
  LabelGP1Max.visible:=ImageGP12.visible;
  LabelSlash3.visible:=ImageGP12.visible;
  GaugeGP1.visible:=ImageGP12.visible;
  ShapeGP1.visible:=ImageGP12.visible;
  igp11.visible:=ImageGP12.visible;
  igp12.visible:=ImageGP12.visible;
  igp13.visible:=ImageGP12.visible;
  ImageGP22.visible:=Datawell.TableOptions3.FieldByName('L28').asboolean;
  ImageGP2.visible:=ImageGP22.visible;
  LabelGP2.visible:=ImageGP22.visible;
  LabelGP2Max.visible:=ImageGP22.visible;
  LabelSlash4.visible:=ImageGP22.visible;
  GaugeGP2.visible:=ImageGP22.visible;
  ShapeGP2.visible:=ImageGP22.visible;
  igp21.visible:=ImageGP22.visible;
  igp22.visible:=ImageGP22.visible;
  igp23.visible:=ImageGP22.visible;
  GaugeEnemy.visible:=Datawell.TableOptions3.FieldByName('L29').asboolean;
  if GaugeEnemy.visible then begin
    ImageEnemy.visible:=enemys[0];
    ImageEnemyLow.visible:=enemys[1];
    ImageEnemyMedian.visible:=enemys[2];
    ImageEnemyHigh.visible:=enemys[3];
    ImageEnemyBetter.visible:=enemys[4];
    ImageEnemy2.visible:=enemys[0];
    ImageEnemyLow2.visible:=enemys[1];
    ImageEnemyMedian2.visible:=enemys[2];
    ImageEnemyHigh2.visible:=enemys[3];
    ImageEnemyBetter2.visible:=enemys[4];
  end;
  GaugeEnemy2.visible:=GaugeEnemy.visible;
  ImageEnemyName.visible:=GaugeEnemy.visible;
  ImageEnemyName2.visible:=GaugeEnemy.visible;
  ShapeEnemy.visible:=GaugeEnemy.visible;
  ShapeEnemy2.visible:=GaugeEnemy.visible;
  LabelEName.visible:=GaugeEnemy.visible;
  LabelEName2.visible:=GaugeEnemy.visible;
end;

procedure TFormMain.MenuHP1BarSkinClick(Sender: TObject);
begin
  DialogOpen3.initialdir:=Datawell.GetDir(2);
  if not DialogOpen3.execute then exit;
  Datawell.SetDir(2,DialogOpen3.filename);
  Datawell.TableOptions3.edit;
  case TComponent(sender).tag of
    1: Datawell.TableOptions3.fieldbyname('S66').asstring:=DialogOpen3.filename;
    2: Datawell.TableOptions3.fieldbyname('S67').asstring:=DialogOpen3.filename;
  end;
  Datawell.TableOptions3.post;
  LoadSkin(TComponent(sender).tag);
end;

procedure TFormMain.MenuHP1BarSkinClearClick(Sender: TObject);
begin
  Datawell.TableOptions3.edit;
  case TComponent(sender).tag of
    1: Datawell.TableOptions3.fieldbyname('S66').asstring:='';
    2: Datawell.TableOptions3.fieldbyname('S67').asstring:='';
  end;
  Datawell.TableOptions3.post;
  LoadSkin(TComponent(sender).tag);
end;

procedure TFormMain.MenuHP1FontClick(Sender: TObject);
var col: TColor;
begin
  case TComponent(sender).tag of
    0: col:=clblack;
    1: col:=clmaroon;
    2: col:=clgreen;
    3: col:=clolive;
    4: col:=clnavy;
    5: col:=clpurple;
    6: col:=clteal;
    7: col:=clsilver;
    8: col:=clgray;
    9: col:=clred;
    10: col:=cllime;
    11: col:=clyellow;
    12: col:=clblue;
    13: col:=clfuchsia;
    14: col:=claqua;
    15: col:=clwhite;
    else raise Exception.CreateFmt('TFormMain.MenuHP1FontClick: invalid sender tag: %d', [TComponent(sender).tag]);
  end;
  Datawell.TableOptions3.edit;
  Datawell.TableOptions3.fieldbyname('I21').asinteger:=col;
  Datawell.TableOptions3.post;
  UpdateHPBars;
end;

procedure TFormMain.MenuHP1BarBackgroundClick(Sender: TObject);
var
  stag, which: integer;
  col: TColor;
begin
  stag:=TComponent(sender).tag;
  if stag >= 200 then begin
    which:=2;
    dec(stag,200);
  end
  else begin
    which:=1;
    dec(stag,100);
  end;
  case stag of
    0: col:=clblack;
    1: col:=clmaroon;
    2: col:=clgreen;
    3: col:=clolive;
    4: col:=clnavy;
    5: col:=clpurple;
    6: col:=clteal;
    7: col:=clsilver;
    8: col:=clgray;
    9: col:=clred;
    10: col:=cllime;
    11: col:=clyellow;
    12: col:=clblue;
    13: col:=clfuchsia;
    14: col:=claqua;
    15: col:=clwhite;
    else raise Exception.CreateFmt('TFormMain.MenuHP1BarBackgroundClick: invalid sender tag: %d', [stag]);
  end;
  Datawell.TableOptions3.edit;
  case which of
    1: Datawell.TableOptions3.fieldbyname('I20').asinteger:=col;
    2: Datawell.TableOptions3.fieldbyname('I22').asinteger:=col;
  end;
  Datawell.TableOptions3.post;
  UpdateHPBars;
end;

procedure TFormMain.LoadHP(index: integer);
var
  b1, b2: TBitMap;
  filename: string;
  im: TImage;
begin
  case index of
    1: filename:=Datawell.exedir+'\HP.bmp';
    2: filename:=Datawell.exedir+'\SP.bmp';
    3: filename:=Datawell.exedir+'\GP1.bmp';
    4: filename:=Datawell.exedir+'\GP2.bmp';
    10: filename:=Datawell.exedir+'\Enemy.bmp';
    11: filename:=Datawell.exedir+'\EnemyLow.bmp';
    12: filename:=Datawell.exedir+'\EnemyMedian.bmp';
    13: filename:=Datawell.exedir+'\EnemyHigh.bmp';
    14: filename:=Datawell.exedir+'\EnemyBetter.bmp';
  end;
  case index of
    1: im:=ImageHP;
    2: im:=ImageSP;
    3: im:=ImageGP1;
    4: im:=ImageGP2;
    10: im:=ImageEnemy;
    11: im:=ImageEnemyLow;
    12: im:=ImageEnemyMedian;
    13: im:=ImageEnemyHigh;
    14: im:=ImageEnemyBetter;
    else raise Exception.CreateFmt('TFormMain.LoadHP: Invalid index value: %d', [index]);
  end;
  if not FileExists(filename) then exit;
  b2:=TBitMap.create;
  b1:=TBitMap.create;
  try
    b1.loadfromfile(filename);
    b2.assign(b1);
    b2.dormant;
    b2.freeimage;
    with im.canvas do begin
      brush.color:=clyellow;
      BrushCopy(bounds(0,0,16,16),b2,bounds(0,0,16,16),clyellow);
    end;
    b2.releasehandle;
  finally
    b1.free;
    b2.free;
  end;
end;

procedure TFormMain.LoadHPImages;
begin
  LoadHP(1);
  LoadHP(2);
  LoadHP(3);
  LoadHP(4);
  LoadHP(10);
  LoadHP(11);
  LoadHP(12);
  LoadHP(13);
  LoadHP(14);
  ImageHP2.picture.bitmap.assign(ImageHP.picture.bitmap);
  ImageSP2.picture.bitmap.assign(ImageSP.picture.bitmap);
  ImageGP12.picture.bitmap.assign(ImageGP1.picture.bitmap);
  ImageGP22.picture.bitmap.assign(ImageGP2.picture.bitmap);
  ImageEnemy2.picture.bitmap.assign(ImageEnemy.picture.bitmap);
  ImageEnemyLow2.picture.bitmap.assign(ImageEnemyLow.picture.bitmap);
  ImageEnemyMedian2.picture.bitmap.assign(ImageEnemyMedian.picture.bitmap);
  ImageEnemyHigh2.picture.bitmap.assign(ImageEnemyHigh.picture.bitmap);
  ImageEnemyBetter2.picture.bitmap.assign(ImageEnemyBetter.picture.bitmap);
end;

procedure TFormMain.DefaultHP1BarFont1Click(Sender: TObject);
var s: integer;
begin
  s:=TMenuItem(sender).tag;
  if s = 0 then s:=10
  else s:=LabelHP.font.size+s;
  if s < 6 then s:=6;
  if s > 14 then s:=14;
  LabelHP.font.size:=s;
  LabelHPMax.font.size:=LabelHP.font.size;
  LabelSP.font.size:=LabelHP.font.size;
  LabelSPMax.font.size:=LabelHP.font.size;
  LabelGP1.font.size:=LabelHP.font.size;
  LabelGP1Max.font.size:=LabelHP.font.size;
  LabelGP2.font.size:=LabelHP.font.size;
  LabelGP2Max.font.size:=LabelHP.font.size;
  LabelEName.font.size:=LabelHP.font.size;
  LabelEName2.font.size:=LabelHP.font.size;
end;

procedure TFormMain.Telnet2SessionConnected(Sender: TTnCnx; Error: Word);
var alreadyconnected: boolean;
begin
  tryingsecond:=false;
  alreadyconnected:=Datawell.connected2;
  Datawell.connected2:=true;
  if alreadyconnected then exit;
  SystemText('Secondary connection to '+Telnet2.host+':'+Telnet2.port+' established',0);
  LEDSecondaryConnected.hint:='Secondary connection: '+Telnet2.host+':'+Telnet2.port;
  PopupSecondaryConnect.enabled:=false;
  PopupSecondaryDisconnect.enabled:=true;
  PanelSecondary.width:=34;
  PanelSecondary.enabled:=true;
  UpdateToolbar;
  UpdateCaption;
  LEDSecondaryConnected.bringtofront;
  ChangeControl(2);
  EditSend.setfocus;
end;

procedure TFormMain.Telnet2SessionClosed(Sender: TTnCnx; Error: Word);
begin
  Datawell.connected2:=false;
  SystemText('Secondary connection to '+Telnet2.host+':'+Telnet2.port+' broken',0);
  PanelSecondary.width:=0;
  PanelSecondary.enabled:=false;
  PopupSecondaryConnect.enabled:=true;
  PopupSecondaryDisconnect.enabled:=false;
  UpdateToolbar;
  UpdateCaption;
  LEDSecondaryDisconnected.bringtofront;
  ChangeControl(1);
  if not panicking then EditSend.setfocus;
end;

procedure TFormMain.MenuSecondaryClick(Sender: TObject);
var
  form: TFormNewConnection;
  mhost, mport, emess, work: string;
  linked, usecr: boolean;
  p: integer;
begin
  if not Datawell.CheckRinged(false,'secondary connection') then exit;
  if not Datawell.connected then begin
    messagedlg('There must be an active primary connection first',
      mtinformation,[mbok],0);
    exit;
  end;
  if tryingsecond then begin
    systemtext('Already trying to connect to: '+Telnet2.host+':'+Telnet2.port+', please wait...',0);
    exit;
  end;
  if Datawell.connected2 then begin
    systemtext('You must disconnect from '+Telnet2.host+':'+Telnet2.port+' first',0);
    exit;
  end;
  form:=TFormNewConnection.create(self);
  form.EditHost.text:=Telnet.host;
  form.EditPort.text:=Telnet.port;
  form.CheckCR.checked:=(Datawell.cr = #13);
  work:=Datawell.TableOptions3.fieldbyname('S63').asstring;
  if work <> '' then begin
    p:=pos('|',work);
    if p > 0 then begin
      form.EditHost.text:=copy(work,1,p-1);
      delete(work,1,p);
      p:=pos('|',work);
      if p > 0 then begin
        form.EditPort.text:=copy(work,1,p-1);
        delete(work,1,p);
        form.CheckCR.checked:=(work <> '');
      end;
    end;
  end;
  form.showmodal;
  linked:=form.linked;
  mhost:=form.EditHost.text;
  mport:=form.EditPort.text;
  usecr:=form.CheckCR.checked;
  form.free;
  if not linked then exit;
  work:=mhost+'|'+mport+'|';
  if usecr then work:=work+'cr';
  with Datawell.TableOptions3 do begin
    edit;
    fieldbyname('S63').asstring:=work;
    post;
  end;
  if usecr then Datawell.cr2:=#13 else Datawell.cr2:=#13+#10;
  Telnet2.host:=mhost;
  Telnet2.port:=mport;
  systemtext('Attempting connection to: '+Telnet2.host+':'+Telnet2.port+'. . .',1);
  tryingsecond:=true;
  try Telnet2.Connect;
    except on E:ESocketException do begin
      emess:=E.message;
      if pos('annot convert',emess) > 0 then
        emess:='No socket available.  Host is unavailable or your connection is bad'
      else if pos('oute to',emess) > 0 then
        emess:='No route to host.  Please check your connection to the internet';
      systemtext(emess,0);
      tryingsecond:=false;
      abort;
    end;
  end;
end;

procedure TFormMain.MenuSecondaryDisconnectClick(Sender: TObject);
begin
  if not Datawell.connected2 then begin
    messagedlg('There is no current secondary connection',mtinformation,[mbok],0);
    exit;
  end;
  Telnet2.close;
  EditSend.setfocus;
end;

procedure TFormMain.MenuSecondaryReverseClick(Sender: TObject);
begin
  if BtnMUD1.down then begin
    if not Datawell.connected2 then begin
      messagedlg('There is no current secondary connection',mtinformation,[mbok],0);
      exit;
    end;
    ChangeControl(2);
    exit;
  end;
  ChangeControl(1);
  exit;
end;

procedure TFormMain.ChangeControl(index: integer);
begin
  if index = 1 then begin
    BtnMUD1.down:=true;
    SystemText('Change: Connection switched to: Primary',0);
  end
  else begin
    BtnMUD2.down:=true;
    SystemText('Change: Connection switched to: Secondary',0);
  end;
  UpdateLED;
end;

procedure TFormMain.UpdateLED;
begin
  BtnMUD1.font.color:=Datawell.TableOptions3.fieldbyname('I26').asinteger;
  BtnMUD2.font.color:=Datawell.TableOptions3.fieldbyname('I27').asinteger;
  if BtnMUD1.down then begin
    PanelLED.color:=Datawell.TableOptions3.fieldbyname('I26').asinteger;
    exit;
  end;
  PanelLED.color:=Datawell.TableOptions3.fieldbyname('I27').asinteger;
end;

procedure TFormMain.BtnMUD1Click(Sender: TObject);
begin
  if TSpeedButton(sender).tag = 1 then SystemText('Click: Connection switched to: Primary',0)
  else SystemText('Click: Connection switched to: Secondary',0);
  UpdateLED;
end;

procedure TFormMain.MenuHotkeysClick(Sender: TObject);
var form: TFormMenu;
begin
  if not Datawell.CheckRinged(true,'menu hotkey customization') then exit;
  form:=TFormMenu.create(self);
  form.showmodal;
  form.free;
  UpdateMenu;
end;

procedure TFormMain.UpdateMenu;
var
  i: integer;
  item: string;
  s: TShortcut;
begin
//Main: UpdateMenu
//Menu: CheckHotkeys
  with Datawell.TableMenu do begin
    first;
    while not EOF do begin
      item:=fieldbyname('Item').asstring;
      if item <> '' then begin
        i:=fieldbyname('Index').asinteger;
        s:=texttoshortcut(fieldbyname('Hotkey').asstring);
        case i of
           1010: MenuPanic.shortcut:=s;
           1020: MenuJumpstart.shortcut:=s;
           1030: MenuLock.shortcut:=s;
           1040: MenuClearKeyhistory.shortcut:=s;
           1050: MenuMapper.shortcut:=s;
           1060: MenuCopyDownloadA.shortcut:=s;
           1070: MenuPasteCursor.shortcut:=s;
           1080: MenuCopyDownload.shortcut:=s;
           1090: MenuClearDownload.shortcut:=s;
           1100: MenuUpload.shortcut:=s;
           1110: MenuDisconnect.shortcut:=s;
           1120: MenuReconnect.shortcut:=s;
           1130: MenuSecondary.shortcut:=s;
           1140: MenuSecondaryDisconnect.shortcut:=s;
           1150: MenuSecondaryReverse.shortcut:=s;
           1155: MenuIO.shortcut:=s;
           1160: MenuExit.shortcut:=s;
           2010: MenuCopy.shortcut:=s;
           2020: MenuCopyToAutotyper.shortcut:=s;
           2030: MenuPaste.shortcut:=s;
           2040: MenuSendDelimited.shortcut:=s;
           2050: MenuPasteDelimited.shortcut:=s;
           2060: MenuCutCommandLine.shortcut:=s;
           2070: MenuCopyCommandLine.shortcut:=s;
           2080: MenuPasteCommandLine.shortcut:=s;
           2090: MenuInsertLineBreak.shortcut:=s;
           2000: MenuInsertEscChar.shortcut:=s;
           2110: MenuInsertBeep.shortcut:=s;
           2120: MenuSendPassword.shortcut:=s;
           2130: MenuSendTextFile.shortcut:=s;
           3010: MenuFind.shortcut:=s;
           3020: MenuFindNext.shortcut:=s;
           3030: MenuClearScrollback.shortcut:=s;
           3040: MenuCaptureScrollback.shortcut:=s;
           3050: MenuLogToFile.shortcut:=s;
           4010: MenuAliases.shortcut:=s;
           4020: MenuMacros.shortcut:=s;
           4030: MenuQuickchars.shortcut:=s;
           4040: MenuNicknames.shortcut:=s;
           4050: MenuTicker.shortcut:=s;
           4060: MenuNext.shortcut:=s;
           4070: MenuClearBuffer.shortcut:=s;
           4080: MenuRecord.shortcut:=s;
           5010: MenuEvents.shortcut:=s;
           5020: MenuQuickEvent.shortcut:=s;
           5040: MenuVars.shortcut:=s;
           5050: MenuSetupGroups.shortcut:=s;
           5060: MenuActivateBASE.shortcut:=s;
           6010: MenuOpenAutotyper.shortcut:=s;
           6020: MenuAutotype.shortcut:=s;
           6030: MenuAutoscribble.shortcut:=s;
           7010: MenuProgramOptions.shortcut:=s;
           7020: MenuShowToolbar.shortcut:=s;
           7030: MenuShowRecordTool.shortcut:=s;
           7040: MenuShowStatusbar.shortcut:=s;
           7050: MenuShowHPBar.shortcut:=s;
           7060: MenuShowHP2Bar.shortcut:=s;
           7070: MenuShowHP3Bar.shortcut:=s;
           7080: MenuShowHP4Bar.shortcut:=s;
           7090: MenuHPBar.shortcut:=s;
           7100: MenuCustomizeToolbar.shortcut:=s;
           7110: MenuHotkeys.shortcut:=s;
           7120: MenuDecreaseFont.shortcut:=s;
           7130: MenuIncreaseFont.shortcut:=s;
           7140: MenuFont.shortcut:=s;
           7150: MenuSetupDisplayColors.shortcut:=s;
           8010: MenuShowCanvas.shortcut:=s;
           8020: MenuShowImagery.shortcut:=s;
           8030: MenuShowChat.shortcut:=s;
           8040: MenuShowTell.shortcut:=s;
           8050: MenuShowCartographer.shortcut:=s;
           8070: MenuShowFiltered.shortcut:=s;
           8080: MenuClearFilteredText.shortcut:=s;
           8090: MenuCloseAllScreens.shortcut:=s;
           9010: MenuMusicOpen.shortcut:=s;
           9020: MenuMusicLoad.shortcut:=s;
           9030: MenuMusicPlay.shortcut:=s;
           9040: MenuMusicPause.shortcut:=s;
           9050: MenuMusicRewind.shortcut:=s;
           9060: MenuMusicPrevious.shortcut:=s;
           9070: MenuMusicNext.shortcut:=s;
           9080: MenuMusicFirst.shortcut:=s;
           9090: MenuMusicLast.shortcut:=s;
           9100: MenuMusicRepeat.shortcut:=s;
           9110: MenuMusicRandomize.shortcut:=s;
        end;
      end;
      next;
    end;
  end;
//Propogate Panic Button shortcut
  FormMap.MenuPanic.shortcut:=MenuPanic.shortcut;
  if screens[0] then screenChat.MenuPanic.shortcut:=MenuPanic.shortcut;
  if screens[1] then screenTell.MenuPanic.shortcut:=MenuPanic.shortcut;
  if screens[2] then screenRoom.MenuPanic.shortcut:=MenuPanic.shortcut;
  if screens[4] then screenImagery.MenuPanic.shortcut:=MenuPanic.shortcut;
  if screens[6] then screenFiltered.MenuPanic.shortcut:=MenuPanic.shortcut;
  if screens[10] then screenCanvas.MenuPanic.shortcut:=MenuPanic.shortcut;
  if screens[11] then screenEditor.MenuDownload.shortcut:=MenuCopyDownloadA.shortcut;
end;

procedure TFormMain.CheckIdlePanic;
begin
  if not Datawell.TableOptions3.Active then exit;
  if not Datawell.TableOptions3.fieldbyname('L48').asboolean then exit;
  if showingdisconnect then exit;
  if panicking then exit;
  inc(Datawell.idle);
  if Datawell.idle < Datawell.TableOptions3.fieldbyname('I28').asinteger then exit;
  Datawell.idle:=0;
  MenuPanic.click;
end;

procedure TFormMain.PopulateComboBox(combo: TComboBox;
  dataset: TCustomClientDataSet; fieldname, textname: string);
var
   table: TClientDataset;
begin
  combo.text:='';
  combo.items.clear;
  table := TClientDataset.create(self);
  table.cloneCursor(dataset, false, false);
  table.active := true;
  table.first;
  while not table.EOF do begin
    combo.items.add(table.fieldbyname(fieldname).asstring);
    table.next;
  end;
  table.free;
  combo.text := textname;
end;

procedure TFormMain.PopulateRecord;
begin
  if EditAlias.visible then
    populateComboBox(EditAlias, Datawell.TableAliases, 'Alias', Datawell.lastalias)
  else
    populateComboBox(EditMacro, Datawell.TableMacros, 'Macro', Datawell.lastmacro);
end;

procedure TFormMain.EditMacroCloseUp(Sender: TObject);
begin
  case TComponent(sender).tag of
    1: if EditAlias.text <> '' then Datawell.lastalias:=EditAlias.text;
    2: if EditMacro.text <> '' then Datawell.lastmacro:=EditMacro.text;
  end;
end;

procedure TFormMain.MenuIOClick(Sender: TObject);
var form: TFormIO;
begin
  if not Datawell.CheckRinged2('import/export') then exit;
  SaveOptions(true);
  form:=TFormIO.create(self);
  form.showmodal;
  form.free;
end;

procedure TFormMain.MenuSendTextFileClick(Sender: TObject);
begin
  DialogOpen4.initialdir:=Datawell.GetDir(2);
  if not DialogOpen4.execute then exit;
  Datawell.SetDir(2,DialogOpen4.filename);
  SendFile(DialogOpen4.filename);
end;

procedure TFormMain.UpdateCanvasVariable(variable, value: string);
begin
  if not screens[10] then exit;
  with screenCanvas do begin
    if Label1.hint = variable then Label1.caption:=value;
    if Label2.hint = variable then Label2.caption:=value;
    if Label3.hint = variable then Label3.caption:=value;
    if Label4.hint = variable then Label4.caption:=value;
    if Label5.hint = variable then Label5.caption:=value;
    if Label6.hint = variable then Label6.caption:=value;
    if Label7.hint = variable then Label7.caption:=value;
    if Label8.hint = variable then Label8.caption:=value;
    if Label9.hint = variable then Label9.caption:=value;
    if Label10.hint = variable then Label10.caption:=value;
    if Label11.hint = variable then Label11.caption:=value;
    if Label12.hint = variable then Label12.caption:=value;
    if Label13.hint = variable then Label13.caption:=value;
    if Label14.hint = variable then Label14.caption:=value;
    if Label15.hint = variable then Label15.caption:=value;
    if Label16.hint = variable then Label16.caption:=value;
    if Label17.hint = variable then Label17.caption:=value;
    if Label18.hint = variable then Label18.caption:=value;
    if Label19.hint = variable then Label19.caption:=value;
    if Label20.hint = variable then Label20.caption:=value;
    if Label21.hint = variable then Label21.caption:=value;
    if Label22.hint = variable then Label22.caption:=value;
    if Label23.hint = variable then Label23.caption:=value;
    if Label24.hint = variable then Label24.caption:=value;
    if Label25.hint = variable then Label25.caption:=value;
    if Label26.hint = variable then Label26.caption:=value;
    if Label27.hint = variable then Label27.caption:=value;
    if Label28.hint = variable then Label28.caption:=value;
    if Label29.hint = variable then Label29.caption:=value;
    if Label30.hint = variable then Label30.caption:=value;
  end;
end;

procedure TFormMain.LoadEditorOptions;
var
  work: string;
  h: integer;
begin
  if not screens[11] then exit;
  screenEditor.MenuPanic.shortcut:=MenuPanic.shortcut;
  screenEditor.MenuDownload.shortcut:=MenuCopyDownloadA.shortcut;
  with screenEditor do begin
    top:=Datawell.TableOptions.fieldbyname('EditorTop').asinteger;
    left:=Datawell.TableOptions.fieldbyname('EditorLeft').asinteger;
    height:=Datawell.TableOptions.fieldbyname('EditorHeight').asinteger;
    width:=Datawell.TableOptions.fieldbyname('EditorWidth').asinteger;
    work:=Datawell.TableOptions.fieldbyname('EditorFontName').asstring;
    if work = '' then work:='Courier New';
    Editor1.font.name:=work;
    h:=Datawell.TableOptions.fieldbyname('EditorFontStyle').asinteger;
    Editor1.font.style:=[];
    case h of
      0: Editor1.font.style:=[];
      1: Editor1.font.style:=[fsbold];
      2: Editor1.font.style:=[fsitalic];
      3: Editor1.font.style:=[fsbold, fsitalic];
    end;
    Editor1.font.size:=Datawell.TableOptions.fieldbyname('EditorFontSize').asinteger;
    LabelFont.caption:=inttostr(Editor1.font.size);
    EditWidth1.font.assign(Editor1.font);
    EditWidth2.font.assign(Editor1.font);
    EditWidth3.font.assign(Editor1.font);
    EditWidth4.font.assign(Editor1.font);
    EditWidth1.font.color:=clblack;
    EditWidth2.font.color:=clblack;
    EditWidth3.font.color:=clblack;
    EditWidth4.font.color:=clblack;
    Editor1.font.color:=Datawell.TableOptions.fieldbyname('EditorFColor').asinteger;
    Editor2.font.assign(Editor1.font);
    Editor3.font.assign(Editor1.font);
    Editor4.font.assign(Editor1.font);
    Editor1.color:=Datawell.TableOptions.fieldbyname('EditorBColor').asinteger;
    Editor2.color:=Datawell.TableOptions.fieldbyname('EditorBColor').asinteger;
    Editor3.color:=Datawell.TableOptions.fieldbyname('EditorBColor').asinteger;
    Editor4.color:=Datawell.TableOptions.fieldbyname('EditorBColor').asinteger;
    MenuEnableWordWrap.checked:=Datawell.TableOptions.fieldbyname('EditorWrap').asboolean;
    Editor1.wordwrap:=MenuEnableWordWrap.checked;
    Editor2.wordwrap:=MenuEnableWordWrap.checked;
    Editor3.wordwrap:=MenuEnableWordWrap.checked;
    Editor4.wordwrap:=MenuEnableWordWrap.checked;
    if Editor1.wordwrap then Editor1.scrollbars:=ssvertical else Editor1.scrollbars:=ssboth;
    Editor2.scrollbars:=Editor1.scrollbars;
    Editor3.scrollbars:=Editor1.scrollbars;
    Editor4.scrollbars:=Editor1.scrollbars;
    MenuSaveAlert.checked:=Datawell.TableOptions.fieldbyname('AutotypeSave').asboolean;
    MenuClearOnAutotype.checked:=Datawell.TableOptions.fieldbyname('EditorClear').asboolean;
    MenuAskOnEmpty.checked:=Datawell.TableOptions.fieldbyname('EditorAsk').asboolean;
    MenuShowWidthBar.checked:=Datawell.TableOptions.fieldbyname('EditorShowWidthbar').asboolean;
    if MenuShowWidthbar.checked then PanelWidth1.height:=16 else PanelWidth1.height:=0;
    PanelWidth2.height:=PanelWidth1.height;
    PanelWidth3.height:=PanelWidth1.height;
    PanelWidth4.height:=PanelWidth1.height;
    if Datawell.TableOptions.fieldbyname('EditorStayOnTop').asboolean then formstyle:=fsstayontop
    else formstyle:=fsnormal;
    MenuStayOnTop.checked:=Datawell.TableOptions.fieldbyname('EditorStayOnTop').asboolean;
    show;
  end;
end;

procedure TFormMain.ExecuteExternal(data: string);
var fname: string;
begin
  fname:=Datawell.subs('/','\',data);
  if not fileexists(fname) then begin
    if fileexists(fname+'.exe') then fname:=fname+'.exe'
    else begin
      fname:=Datawell.exedir+'\'+fname;
      if not fileexists(fname) then begin
        if fileexists(fname+'.exe') then fname:=fname+'.exe'
        else begin
          SystemText('File does not exist: '+data,0);
          exit;
        end;
      end;
    end;
  end;
  systemtext('Executing: '+data,0);
  Datawell.EXE(data,'','c:\',SW_SHOW);
end;

procedure TFormMain.MenuScottClick(Sender: TObject);
var mess: TStringList;
begin
  mess:=TStringList.create;
  mess.add('With your looks, how can you go wrong?');
  mess.add('I''m leaning towards yes');
  mess.add('Yep');
  mess.add('Absofreakinglutely yes!');
  mess.add('Without a doubt yes');
  mess.add('I''d go for it');
  mess.add('My gut says yes');
  mess.add('Yeah, it sounds good');
  mess.add('Things look positive');
  mess.add('Yes');
  mess.add('No way');
  mess.add('No way in hell');
  mess.add('Maybe, but I wouldn''t count on it');
  mess.add('Nope');
  mess.add('Absolutely not');
  mess.add('Nononononono');
  mess.add('I''d hedge against that');
  mess.add('No');
  mess.add('Nah, it''s just not looking good');
  mess.add('If I said yes, I''d be lying');
  mess.add('Holy crap no!');
  mess.add('Holy crap yes!');
  systemtext('Scott says: '+mess[random(mess.count)],0);
  mess.free;
end;

procedure TFormMain.MenuShowRoomClick(Sender: TObject);
begin
  if not screens[2] then LoadScreen(2);
end;

procedure TFormMain.AddParsing;
var
  p: integer;
  work, work2: string;
begin
  if not Datawell.TableOptions3.fieldbyname('L58').asboolean then exit;
  if Datawell.TableOptions3.fieldbyname('L59').asboolean then
    work:=lowercase(MUDAnsi.flines[MUDAnsi.flines.count-2])+' '
  else
    work:=MUDAnsi.flines[MUDAnsi.flines.count-2]+' ';
  p:=pos(' ',work);
  while p > 0 do begin
    work2:=copy(work,1,p-1);
    delete(work,1,p);
    if length(work2) >= Datawell.TableOptions3.fieldbyname('I33').asinteger then begin
      while Parsing.indexof(work2) >= 0 do Parsing.delete(Parsing.indexof(work2));
      Parsing.add(work2);
      if Parsing.count > Datawell.TableOptions3.fieldbyname('I32').asinteger then Parsing.delete(0);
    end;
    p:=pos(' ',work);
  end;
  ParsingI:=Parsing.count-1;
end;

procedure TFormMain.MenuTabClick(Sender: TObject);
begin
  if not Datawell.TableOptions3.fieldbyname('L58').asboolean then exit;
  if ParsingI = (Parsing.count-1) then ParsingI:=Parsing.count;
  LocateParsing('up');
end;

procedure TFormMain.MenuTabShiftClick(Sender: TObject);
begin
  if not Datawell.TableOptions3.fieldbyname('L58').asboolean then exit;
  if ParsingI = (Parsing.count-1) then ParsingI:=0;
  LocateParsing('down');
end;

procedure TFormMain.LocateParsing(dir: string);
var
  data: string;
  found: boolean;
begin
  homed:=true;
  if Parsing.count < 1 then exit;
  if ParsePos > 0 then EditSend.text:=copy(EditSend.text,1,ParsePos);
  if EditSend.sellength > 0 then begin
    if EditSend.selstart = 0 then EditSend.text:=copy(EditSend.text,1,EditSend.sellength)
    else EditSend.text:=copy(EditSend.text,1,EditSend.selstart);
  end;
  EditSend.sellength:=0;
  data:=EditSend.text;
  while pos(' ',data) > 0 do delete(data,1,pos(' ',data));
  if length(data) < 1 then exit;
  ParsePos:=length(EditSend.text);
  //Load up well items
{
  if ParsingI = Parsing.count then begin
    with Datawell.TableOptions3 do begin
      if fieldbyname('S10').asstring <> '' then Parsing.add(fieldbyname('S10').asstring);
      if fieldbyname('S11').asstring <> '' then Parsing.add(fieldbyname('S11').asstring);
      if fieldbyname('S12').asstring <> '' then Parsing.add(fieldbyname('S12').asstring);
      if fieldbyname('S13').asstring <> '' then Parsing.add(fieldbyname('S13').asstring);
      if fieldbyname('S14').asstring <> '' then Parsing.add(fieldbyname('S14').asstring);
      if fieldbyname('S15').asstring <> '' then Parsing.add(fieldbyname('S15').asstring);
      if fieldbyname('S16').asstring <> '' then Parsing.add(fieldbyname('S16').asstring);
      if fieldbyname('S17').asstring <> '' then Parsing.add(fieldbyname('S17').asstring);
      ParsingI:=Parsing.count;
    end;
  end;
}
  found:=false;
  if dir = 'up' then begin
    for ParsingI:=ParsingI-1 downto 0 do begin
      if copy(Parsing[ParsingI],1,length(data)) = data then begin
        found:=true;
        break;
      end;
    end;
  end
  else begin
    for ParsingI:=ParsingI+1 to Parsing.count-1 do begin
      if copy(Parsing[ParsingI],1,length(data)) = data then begin
        found:=true;
        break;
      end;
    end;
  end;
  if found then begin
    EditSend.text:=EditSend.text+copy(Parsing[ParsingI],length(data)+1,999);
    EditSend.selstart:=length(EditSend.text);
    EditSend.sellength:=0;
  end
  else begin
    EditSend.selstart:=length(EditSend.text);
    EditSend.sellength:=0;
    if dir = 'up' then ParsingI:=Parsing.count-1
    else ParsingI:=0;
  end;
end;

procedure TFormMain.MenuMusicOpenClick(Sender: TObject);
var
  form: TFormMusic;
  isplaying, didchange: boolean;
begin
  if not Datawell.CheckRinged2('music playlist editor') then exit;
  isplaying:=MP.mode = mpplaying;
  if isplaying then begin
    MP.hint:='a';
    MP.stop;
  end;
  form:=TFormMusic.create(self);
  form.showmodal;
  didchange:=form.didchange;
  form.free;
  if not didchange then begin
    if isplaying then MP.play;
    exit;
  end;
  if Datawell.playlist.count > 0 then begin
    Datawell.playindex:=0;
    refresh;
    PlayMusic(Datawell.playlist[Datawell.playindex],false);
    show;
  end;
  UpdateMusic;
end;

procedure TFormMain.MenuMusicNextClick(Sender: TObject);
var dir: integer;
begin
  dir:=(sender as TComponent).tag;
  if (dir < 0) and (Datawell.playindex <= 0) then begin
    SystemText('You are at the beginning of the playlist',0);
    exit;
  end;
  if (dir > 0) and (Datawell.playindex >= Datawell.playlist.count-1) then begin
    SystemText('You are at the end of the playlist',0);
    exit;
  end;
  inc(Datawell.playindex,dir);
  MenuMusicPause.click;
  if PlayMusic(Datawell.playlist[Datawell.playindex],false) = 0 then begin
    systemtext('Playlist song does not exist',0);
    exit;
  end;
  UpdateMusic;
end;

procedure TFormMain.MenuMusicFirstClick(Sender: TObject);
var dir: integer;
begin
  dir:=(sender as TComponent).tag;
  if dir < 0 then begin
    if Datawell.playindex <= 0 then begin
      SystemText('You are at the beginning of the playlist',0);
      exit;
    end
    else Datawell.playindex:=0;
  end;
  if dir > 0 then begin
    if Datawell.playindex >= Datawell.playlist.count-1 then begin
      SystemText('You are at the end of the playlist',0);
      exit;
    end
    else Datawell.playindex:=Datawell.playlist.count-1;
  end;
  MenuMusicPause.click;
  if PlayMusic(Datawell.playlist[Datawell.playindex],false) = 0 then begin
    systemtext('Playlist song does not exist',0);
    exit;
  end;
  UpdateMusic;
end;

procedure TFormMain.MenuMusicLoadClick(Sender: TObject);
var didfail: boolean;
begin
  DialogOpenPlaylist.initialdir:=Datawell.GetDir(5);
  if not DialogOpenPlaylist.execute then exit;
  Datawell.SetDir(5,DialogOpenPlaylist.filename);
  didfail:=false;
  try Datawell.playlist.loadfromfile(DialogOpenPlaylist.filename);
  except on EFOpenError do didfail:=true; end;
  if didfail then exit;
  while Datawell.playlist.count > 100 do Datawell.playlist.delete(Datawell.playlist.count-1);
  Datawell.playindex:=0;
  refresh;
  PlayMusic(Datawell.playlist[Datawell.playindex],false);
  show;
end;

procedure TFormMain.MenuMusicRepeatClick(Sender: TObject);
begin
  MenuMusicRepeat.checked:=not MenuMusicRepeat.checked;
  repeatmusic:=0;
  if MenuMusicRepeat.checked then MenuMusicRandomize.checked:=false;
end;

procedure TFormMain.MenuMusicRandomizeClick(Sender: TObject);
begin
  TMenuItem(sender).checked:=not TMenuItem(sender).checked;
  if MenuMusicRandomize.checked then MenuMusicRepeat.checked:=false;
  UpdateMusic;
end;

procedure TFormMain.TimerMusicTimer(Sender: TObject);
begin
  TimerMusic.enabled:=false;
  LabelStatus.caption:=' '+roomshortstring;
  LabelStatus.font.color:=clblack;
  PanelStatus.color:=clbtnface;
end;

function TFormMain.PlayMusic(filename: string; dontplay: boolean): integer;
var
  didfail: boolean;
  stext, f, ofile: string;
begin
  result:=0;
  didfail:=false;
  if filename = '' then exit;
  ofile:=filename;
//  filename:=lowercase(filename);
  //Check if file exists
  if not fileexists(filename) then begin
    //File doesn't exist
    //Check the media dir for the file
    if fileexists(filename+'.mid') then filename:=filename+'.mid'
    else if fileexists(filename+'.rmi') then filename:=filename+'.rmi'
    else if fileexists(filename+'.mp3') then filename:=filename+'.mp3'
    else begin
      filename:=Datawell.getsounddir+'\'+filename;
      if not fileexists(filename) then begin
        //File doesn't exist
        //See if there's a .mid/.rmi/.mp3 file with that name
        if fileexists(filename+'.mid') then filename:=filename+'.mid'
        else if fileexists(filename+'.rmi') then filename:=filename+'.rmi'
        else if fileexists(filename+'.mp3') then filename:=filename+'.mp3';
      end;
    end;
  end;
  if not fileexists(filename) then exit;
  result:=2;
  MP.notify:=false;
  MP.filename:=filename;
  f:=extractfilename(Datawell.playlist[Datawell.playindex]);
  f:=copy(f,1,length(f)-4);
  stext:=LabelStatus.caption;
  LabelStatus.font.color:=clwhite;
  PanelStatus.color:=clnavy;
  LabelStatus.caption:=' Loading Song: '+f;
  PanelStatus.repaint;
  try MP.open; except on EMCIDeviceError do didfail:=true; end;
  if not didfail then begin
    MP.notify:=true;
    MP.hint:='a';
    if not dontplay then begin
      MP.play;
      LabelStatus.caption:=' Playing song: '+f;
      PanelStatus.repaint;
      TimerMusic.enabled:=false;
      TimerMusic.enabled:=true;
    end
    else begin
      LabelStatus.caption:=stext;
      LabelStatus.font.color:=clblack;
      PanelStatus.color:=clbtnface;
    end;
    result:=1;
    exit;
  end;
  if Datawell.TableGlobals.fieldbyname('ShowWarnings').asboolean then
    systemtext('That file is already opened by another media device or',0);
    systemtext('you are missing the device driver for the file: '+MP.filename,0);
    systemtext('Please visit www.microsoft.com to download the latest Media Player drivers',0);
  MP.filename:='';
  LabelStatus.caption:=stext;
  LabelStatus.font.color:=clblack;
  PanelStatus.color:=clbtnface;
end;

procedure TFormMain.UpdateMusic;
var
  f, playnow, playprevious, playnext, playfirst, playlast: string;
begin
  //There is something in the playlist
  if Datawell.playindex >= 0 then begin
    if MP.mode = mpplaying then begin
      BtnMusicPlay.enabled:=MenuMusicRandomize.checked;
      BtnMusicPause.enabled:=true;
    end
    else begin
      BtnMusicPlay.enabled:=true;
      BtnMusicPause.enabled:=false;
    end;
    BtnMusicRewind.enabled:=true;
    BtnMusicPrevious.enabled:=(Datawell.playindex > 0);
    BtnMusicNext.enabled:=(Datawell.playindex < Datawell.playlist.count-1);
  end
  //There is nothing in the playlist
  else begin
    BtnMusicPlay.enabled:=false;
    BtnMusicRewind.enabled:=false;
    BtnMusicPause.enabled:=false;
    BtnMusicPrevious.enabled:=false;
    BtnMusicNext.enabled:=false;
    BtnMusicFirst.enabled:=false;
    BtnMusicLast.enabled:=false;
  end;
  //Update the dependent buttons and the corresponding menu-items
  BtnMusicFirst.enabled:=BtnMusicPrevious.enabled;
  BtnMusicLast.enabled:=BtnMusicNext.enabled;
  MenuMusicPlay.enabled:=BtnMusicPlay.enabled;
  MenuMusicRewind.enabled:=BtnMusicRewind.enabled;
  MenuMusicPause.enabled:=BtnMusicPause.enabled;
  MenuMusicPrevious.enabled:=BtnMusicPrevious.enabled;
  MenuMusicNext.enabled:=BtnMusicNext.enabled;
  MenuMusicFirst.enabled:=BtnMusicPrevious.enabled;
  MenuMusicLast.enabled:=BtnMusicNext.enabled;
  //Update the button hints and menu-item captions
  playnow:='';
  playprevious:='';
  playnext:='';
  //Figure current file
  if Datawell.playindex >= 0 then begin
    f:=extractfilename(Datawell.playlist[Datawell.playindex]);
    f:=copy(f,1,length(f)-4);
    playnow:=f;
  end;
  if Datawell.playindex > 0 then begin
    //Figure previous file
    f:=extractfilename(Datawell.playlist[Datawell.playindex-1]);
    f:=copy(f,1,length(f)-4);
    playprevious:=f;
    //Figure first file
    f:=extractfilename(Datawell.playlist[0]);
    f:=copy(f,1,length(f)-4);
    playfirst:=f;
  end;
  if Datawell.playindex < (Datawell.playlist.count-1) then begin
    //Figure next file
    f:=extractfilename(Datawell.playlist[Datawell.playindex+1]);
    f:=copy(f,1,length(f)-4);
    playnext:=f;
    //Figure last file
    f:=extractfilename(Datawell.playlist[Datawell.playlist.count-1]);
    f:=copy(f,1,length(f)-4);
    playlast:=f;
  end;
  //Update play items
  BtnMusicPlay.hint:='Play song';
  MenuMusicPlay.caption:='&Play Song';
  BtnMusicPause.hint:='Pause song';
  MenuMusicPause.caption:='Pa&use Song';
  if playnow <> '' then begin
    if (MP.mode = mpplaying) and (MenuMusicRandomize.checked) then begin
      BtnMusicPlay.hint:='Play a random song from the playlist';
      MenuMusicPlay.caption:='&Play a random song from the playlist';
    end
    else begin
      BtnMusicPlay.hint:=BtnMusicPlay.hint+': '+playnow;
      MenuMusicPlay.caption:=MenuMusicPlay.caption+': '+playnow;
    end;
    BtnMusicPause.hint:=BtnMusicPause.hint+': '+playnow;
    MenuMusicPause.caption:=MenuMusicPause.caption+': '+playnow;
  end;
  //Update previous items
  BtnMusicPrevious.hint:='Goto previous song';
  MenuMusicPrevious.caption:='Goto Pre&vious Song';
  BtnMusicFirst.hint:='Goto first song';
  MenuMusicFirst.caption:='Goto &First Song';
  if playprevious <> '' then begin
    BtnMusicPrevious.hint:=BtnMusicPrevious.hint+': '+playprevious;
    MenuMusicPrevious.caption:=MenuMusicPrevious.caption+': '+playprevious;
    BtnMusicFirst.hint:=BtnMusicFirst.hint+': '+playfirst;
    MenuMusicFirst.caption:=MenuMusicFirst.caption+': '+playfirst;
  end;
  //Update next items
  BtnMusicNext.hint:='Goto next song';
  MenuMusicNext.caption:='Goto Ne&xt Song';
  BtnMusicLast.hint:='Goto last song';
  MenuMusicLast.caption:='Goto La&st Song';
  if playnext <> '' then begin
    BtnMusicNext.hint:=BtnMusicNext.hint+': '+playnext;
    MenuMusicNext.caption:=MenuMusicNext.caption+': '+playnext;
    BtnMusicLast.hint:=BtnMusicLast.hint+': '+playlast;
    MenuMusicLast.caption:=MenuMusicLast.caption+': '+playlast;
  end;
end;

procedure TFormMain.MenuCopyDownloadAClick(Sender: TObject);
begin
  MenuOpenAutotyperClick(Sender);
  if screens[11] then begin
    screenEditor.MenuNewClick(sender);
    screenEditor.ActiveEditor.lines.assign(Download);
    screenEditor.ActiveEditor.sellength:=0;
    screenEditor.ActiveEditor.selstart:=0;
  end;
end;

procedure TFormMain.SuperClick(Sender: TObject);
begin
  MenuOpenAutotyperClick(Sender);
  if screens[11] then begin
    screenEditor.MenuNewClick(sender);
    MemoCopy.pastefromclipboard;
    screenEditor.ActiveEditor.lines.assign(Download);
    screenEditor.ActiveEditor.lines.insert(0,'a');
    screenEditor.ActiveEditor.lines.insert(0,'1,$d');
    screenEditor.ActiveEditor.lines.insert(0,'ed '+MemoCopy.text);
    screenEditor.ActiveEditor.lines.add('.');
    screenEditor.ActiveEditor.lines.add('x');
    screenEditor.ActiveEditor.lines.add('ul');
    screenEditor.ActiveEditor.sellength:=0;
    screenEditor.ActiveEditor.selstart:=0;
  end;
end;

procedure TFormMain.MenuAutoscribbleClick(Sender: TObject);
var
  form: TFormNote;
  i, h: integer;
  lins: TStringList;
  work: string;
begin
  if not Datawell.CheckRinged2('Autoscribble') then exit;
  form:=TFormNote.create(self);
  with form do begin
    work:=Datawell.TableOptions.fieldbyname('EditorFontName').asstring;
    if work = '' then work:='Courier New';
    Editor1.font.name:=work;
    h:=Datawell.TableOptions.fieldbyname('EditorFontStyle').asinteger;
    Editor1.font.style:=[];
    case h of
      0: Editor1.font.style:=[];
      1: Editor1.font.style:=[fsbold];
      2: Editor1.font.style:=[fsitalic];
      3: Editor1.font.style:=[fsbold, fsitalic];
    end;
    Editor1.font.size:=Datawell.TableOptions.fieldbyname('EditorFontSize').asinteger;
    Editor1.font.color:=Datawell.TableOptions.fieldbyname('EditorFColor').asinteger;
    Editor1.color:=Datawell.TableOptions.fieldbyname('EditorBColor').asinteger;
  end;
  form.showmodal;
  lins:=TStringlist.create;
  if form.doat then lins.assign(form.Editor1.lines);
  form.free;
  if lins.count > 0 then begin
    for i:=0 to lins.count-1 do ParseMain(lins[i],2);
  end;
  lins.free;
end;

procedure TFormMain.LabelENameDblClick(Sender: TObject);
begin
  LabelEName.caption:='';
  LabelEName2.caption:='';
end;

procedure TFormMain.LogSession;
var
  F: TextFile;
  xlast: integer;
  didfind: boolean;
begin
  if not Datawell.TableGlobals.fieldbyname('L13').asboolean then exit;
  xlast:=Datawell.TableGlobals.fieldbyname('Last').asinteger;
  if xlast < 2 then exit;
  try AssignFile(F,Datawell.exedir+'\sessions.log');
    except on EInOutError do exit;
  end;
  if not fileexists(Datawell.exedir+'\sessions.log') then begin
    try Rewrite(F); except on EInOutError do exit; end;
  end;
  try Append(F); except on EInOutError do exit; end;
  try WriteLn(F,Telnet.host+':'+Telnet.port+':'+inttostr(xlast));
    except on EInOutError do exit;
  end;
  try CloseFile(F); except on EInOutError do exit; end;
  with Datawell.TableSessions do begin
    Active := true;
    first;
    didfind:=false;
    while not EOF do begin
      if (fieldbyname('Host').asstring = Telnet.host) and
         (fieldbyname('Port').asstring = Telnet.port) then begin
        didfind:=true;
        break;
      end;
      next;
    end;
    if didfind then begin
      edit;
      fieldbyname('Minutes').asinteger:=fieldbyname('Minutes').asinteger+xlast;
      fieldbyname('Connections').asinteger:=fieldbyname('Connections').asinteger+1;
    end
    else begin
      append;
      fieldbyname('Host').asstring:=Telnet.host;
      fieldbyname('Port').asstring:=Telnet.port;
      fieldbyname('Minutes').asinteger:=xlast;
      fieldbyname('Created').asdatetime:=now;
      fieldbyname('Connections').asinteger:=1;
    end;
    post;
  end;
end;

procedure TFormMain.SessionLogs1Click(Sender: TObject);
var form: TFormSession;
begin
  form:=TFormSession.create(self);
  form.showmodal;
  form.free;
end;

procedure TFormMain.TimerRepeatTimer(Sender: TObject);
begin
  if Datawell.repeatstring = '' then begin
    TimerRepeat.enabled:=false;
    exit;
  end;
  ParseMain(Datawell.repeatstring,9);
end;

end.
